
filecontents
환경 에 관한 두 가지 질문은 다음과 같습니다 .
기존 파일에 콘텐츠를 추가하거나 최소한 외부 파일을 열어 여러
filecontents
환경의 콘텐츠를 동일한 외부 파일에 추가하는 것이 가능합니까?환경 에 의해 외부 파일에 몇 줄이 기록되었는지 알 수 있습니까
filecontents
?
답변1
filecontents
환경은 내용을 한 줄씩 처리하고 읽고 환경이 종료되었는지 확인한 다음 쓰기 때문에 줄 수를 세기 가 쉽습니다. 카운터를 만들어서 한 줄을 쓸 때마다 추가하면 됩니다.
추가하는 것이 더 까다롭습니다. 우선, TeX(적어도 Lua 없이)는 "추가" 권한이 있는 파일을 열 수 없으므로 제외됩니다. 파일을 열어 둔 다음 나중에 쓰기를 다시 시작하는 아이디어는 처음에는 더 쉬워 보이지만 여러 환경에 걸쳐 많은 변수를 저장해야 하며 그런 다음 file , a
그런 b
다음 추가 할 수 없습니다. 에게 a
.
아래 코드에서 \filecontents@preappend
매크로( append
옵션이 사용되는 경우)는 임시 매크로에 대한 인수의 파일을 읽은 다음 \filecontents@append
읽기 매크로를 입력 스트림에서 환경의 실제 콘텐츠 앞에 넣으므로 마치 다음과 같이 작동합니다. 한 번에 모든 것을 입력했습니다. 옵션 은 및 옵션을 append
의미합니다 .overwrite
noheader
압축을 위해 코드를 패치로 작성하려고 했는데 분명히 명령을 패치하면 문자가 손실되고 ^^J
헤더가 한 줄로 축소되므로 이는 의 완전한 재정의이지만 \filec@ntents
변경된 줄이 표시됩니다.
\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \FileSize \file_size:n
\ExplSyntaxOff
\makeatletter
\begingroup%
\@tempcnta=1
\loop
\catcode\@tempcnta=12 %
\advance\@tempcnta\@ne %
\ifnum\@tempcnta<32 %
\repeat %
\catcode`\^^M\active
\catcode`\^^L\active\let^^L\relax
\catcode`\^^I\active
\gdef\filec@ntents#1{%
\set@curr@file{\filec@ntents@checkdir#1}%
\edef\q@curr@file{\expandafter\quote@name\expandafter{\@curr@file}}%
\filecontents@preappend% <- ADDED for appending
\gaborit@reset@counter% <- ADDED for counting lines
\gaborit@reset@append% <- ADDED for counting lines
\openin\@inputcheck\q@curr@file \space %
\ifeof\@inputcheck%
\@latex@warning@no@line%
{Writing file `\@currdir\@curr@file'}%
\chardef\reserved@c15 %
\ch@ck7\reserved@c\write%
\immediate\openout\reserved@c\q@curr@file\relax%
\else%
\if@filesw%
\@latex@warning@no@line%
{File `\@curr@file' already \filec@ntents@where.\MessageBreak%
Not generating it from this source}%
\let\gaborit@step@counter\@empty% <- ADDED for counting lines
\let\gaborit@count@header\@empty% <- ADDED for counting lines
\let\write\@gobbletwo%
\let\closeout\@gobble%
\else%
\edef\reserved@a{#1}%
\edef\reserved@a{\detokenize\expandafter{\reserved@a}}%
\edef\reserved@b{\detokenize\expandafter{\jobname}}%
\ifx\reserved@a\reserved@b%
\@fileswtrue%
\else%
\edef\reserved@b{\reserved@b\detokenize{.tex}}%
\ifx\reserved@a\reserved@b
\@fileswtrue%
\fi%
\fi%
\chardef\reserved@c15 %
\ch@ck7\reserved@c\write%
\if@filesw% % Foul ... trying to overwrite \jobname!
\@latex@error{Trying to overwrite `\jobname.tex'}{You can't %
write to the file you a reading from!\MessageBreak%
Data is written to screen instead.}%
\else%
\@latex@warning@no@line%
{Writing or overwriting file `\@currdir\@curr@file'}%
\immediate\openout\reserved@c#1\relax%
\fi%
\fi%
\fi%
\closein\@inputcheck%
\if@tempswa%
\gaborit@count@header% <- ADDED for counting lines
\immediate\write\reserved@c{%
\@percentchar\@percentchar\space%
\expandafter\@gobble\string\LaTeX2e file `\@curr@file'^^J%
\@percentchar\@percentchar\space generated by the %
`\@currenvir' \expandafter\@gobblefour\string\newenvironment^^J%
\@percentchar\@percentchar\space from source `\jobname' on %
\number\year/\two@digits\month/\two@digits\day.^^J%
\@percentchar\@percentchar}%
\fi%
\let\do\@makeother\dospecials%
\count@ 128\relax%
\loop%
\catcode\count@ 11\relax%
\advance\count@ \@ne%
\ifnum\count@<\@cclvi%
\repeat%
\edef\E{\@backslashchar end\string{\@currenvir\string}}%
\edef\reserved@b{%
\def\noexpand\reserved@b%
####1\E####2\E####3\relax}%
\reserved@b{%
\ifx\gaborit@reset@append##1\relax% <- ADDED for counting lines
\gaborit@reset@append% <- ADDED for counting lines
\else% <- ADDED for counting lines
\ifx\relax##3\relax%
\immediate\write\reserved@c{##1}%
\gaborit@step@counter% <- ADDED for counting lines
\else%
\edef^^M{\noexpand\end{\@currenvir}}%
\ifx\relax##1\relax%
\else%
\@latex@warning{Writing text `##1' before %
\string\end{\@currenvir}\MessageBreak as last line of \@curr@file}%
\immediate\write\reserved@c{##1}%
\gaborit@step@counter% <- ADDED for counting lines
\fi%
\ifx\relax##2\relax%
\else%
\@latex@warning{%
Ignoring text `##2' after \string\end{\@currenvir}}%
\fi%
\fi%
\fi% <- ADDED for counting lines
^^M}%
\catcode`\^^L\active%
\let\L\@undefined%
\def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
\catcode`\^^I\active%
\let\I\@undefined%
\def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
\catcode`\^^M\active%
\edef^^M##1^^M{%
\noexpand\reserved@b##1\E\E\relax}%
\filecontents@append}% <- ADDED for appending
%
% Code for append
\gdef\gaborit@pre@append{%
\begingroup%
\catcode`\^^L\active%
\catcode`\^^I\active%
\catcode`\^^M\active%
\let\do\@makeother\dospecials%
\count@ 128\relax%
\loop%
\catcode\count@ 11\relax%
\advance\count@ \@ne%
\ifnum\count@<\@cclvi%
\repeat%
\let^^M\relax%
\edef\gaborit@tmpa{\FileSize{\q@curr@file}}%
\ifnum\expandafter\@car\gaborit@tmpa\@nil=0\relax%
\endgroup \def\gaborit@append{^^M\gaborit@reset@append}%
\else%
\everyeof{\noexpand}%
\edef\gaborit@tmpa{\@@input\q@curr@file \space}%
\edef\x{\endgroup%
\edef\noexpand\gaborit@append{%
\noexpand\gaborit@trim@EOF\gaborit@tmpa\noexpand\gaborit@EOF}}\x%
\fi%
\filec@ntents@overwrite%
\filec@ntents@noheader}%
\gdef\gaborit@trim@EOF#1^^M\gaborit@EOF{^^M#1%
^^M\noexpand\gaborit@reset@append}%
\endgroup%
\def\filec@ntents@append{%
\let\filecontents@preappend\gaborit@pre@append
\def\filecontents@append{\gaborit@append}}
\let\filecontents@preappend\@empty
\let\filecontents@append\@empty
%
% For counting lines
\newcounter{FC@total@lines}
\newcounter{FC@lines}
\def\gaborit@reset@counter{\setcounter{FC@total@lines}{0}}
\def\gaborit@reset@append{\setcounter{FC@lines}{0}}
\def\gaborit@step@counter{%
\stepcounter{FC@total@lines}%
\stepcounter{FC@lines}}
\def\gaborit@count@header{%
\addtocounter{FC@total@lines}{4}%
\addtocounter{FC@lines}{4}} % Number of lines in the header
\makeatother
\begin{filecontents}[overwrite]{testfile.tex}
a
b
c
\end{filecontents}
\typeout{\arabic{FC@total@lines} lines written; \arabic{FC@lines} appended}
\begin{filecontents}[append]{testfile.tex}
d
e
f
g
\end{filecontents}
\typeout{\arabic{FC@total@lines} lines written; \arabic{FC@lines} appended}
\begin{document}
\end{document}
이 코드를 실행하면 TeX는 터미널에 다음을 인쇄합니다.
LaTeX Warning: Writing or overwriting file `./testfile.tex'.
7 lines written; 7 appended
(./testfile.tex)
LaTeX Warning: Writing or overwriting file `./testfile.tex'.
11 lines written; 4 appended
( FC@total@lines
파일의 총 라인 수를 보유하고 카운터 FC@lines
는 추가된 라인 수만 보유합니다) 파일에는 다음이 testfile.tex
포함됩니다.
%% LaTeX2e file `testfile.tex'
%% generated by the `filecontents' environment
%% from source `test' on 2019/12/20.
%%
a
b
c
d
e
f
g
언급한 대로 다음을 수행할 때:
\begin{filecontents*}{testfile.tex}
\end{filecontents*}
%
\begin{filecontents}[append]{testfile.tex}
a
\end{filecontents}
(즉, 아무것도 쓰지 않고 다음 줄을 추가합니다. a
) 얻는 파일은 다음과 같습니다.
a
그 이유는 TeX가 빈 파일을 읽을 때 해당 파일을 하나의 빈 줄 1 이 있는 파일인 것처럼 처리하기 때문입니다. 따라서 두 경우를 쉽게 구별할 수 없으며 덜 나쁜 것을 선택해야 합니다. 빈 파일에 추가할 때 파일 시작 부분에 줄을 추가하거나, 단일 빈 줄이 포함된 파일에 쓸 때 빈 줄을 제거합니다.
그러나 pdfTeX에 도입된 파일 유틸리티(현재 다른 엔진에서도 사용 가능)를 사용하면 파일 크기(바이트 단위)를 쿼리할 수 있으므로 빈 파일에 대해 다른 동작을 가질 수 있습니다. 코드에서는 존재하지 않는 파일을 처리해야 하는 것을 피하기 위해 expl3
'를 사용했습니다.\file_size:n
1. 이 테스트 파일을 통해 이를 확인할 수 있습니다.
\catcode`\@=11
\newwrite\test
\def\testit#1{\immediate\openout\test \jobname.testfile\relax #1%
{\catcode`\^^M=13 \everyeof{\noexpand}%
\edef\tmpa{\ifdefined\@@input \@@input \else \input \fi \jobname.testfile }\show\tmpa}%
\immediate\closeout\test}%
\testit{}% empty file
\testit{\immediate\write\test{}}% single empty line
\csname stop\endcsname\bye
\endlinechar
내 생각에 이 동작은 TeX가 모든 줄의 끝에 를 추가하는 방식 때문이라고 생각합니다 . 빈 파일을 읽을 때 여전히 한 줄(비어 있더라도)을 읽은 다음 \endlinechar
( ^^M
)를 삽입하면 파일에 빈 줄이 하나 있는 것처럼 보입니다.