我尝试使用 TeX\immediate\write
命令在外部文件中写入一些内容。
\documentclass{scrartcl}
\begin{document}
\newwrite\tempfile
\immediate\openout\tempfile=lists.tex
\immediate\write\tempfile{line1}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\closeout\tempfile
\input{lists}
\end{document}
有没有方法可以在代码的后面替换这个 lists.tex 中的一行(例如“line2”)?
答案1
TeX 不允许您以附加或覆盖权限打开文件:只存在读取和写入。您可以通过读取文件、替换要替换的内容,然后重写来伪造该行为。
以下是andexpl3
的实现,它将替换给定的一个或所有出现的\replacelineonce
\replacelineall
细绳在文件中。语法为:
\replacelineonce{<file>}{<search string>}{<replacement>}
{<true code>}{<false code>}
代码将逐行读取<file>
字符串(像\
和{
等字符没有其特殊含义),查找<search string>
(仅匹配整行),如果找到,将替换为<replacement>
。替换后,文件将使用更改后的内容重写。如果进行了任何替换,则<true code>
在最后执行 ,否则<false code>
执行 。如果输入文件不存在,则会引发错误并<false code>
执行 。\replacelineonce
将在第一次替换后停止,而\replacelineall
将替换所有出现的内容。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \replacelineonce { m m m m m }
{ \mountain_replace_once:nnnTF {#1} {#2} {#3} {#4} {#5} }
\NewDocumentCommand \replacelineall { m m m m m }
{ \mountain_replace_all:nnnTF {#1} {#2} {#3} {#4} {#5} }
\tl_new:N \l__mountain_tmpa_tl
\tl_new:N \l__mountain_file_seq
\bool_new:N \l__mountain_replaced_bool
\ior_new:N \l__mountain_replace_ior
\iow_new:N \l__mountain_replace_iow
\prg_new_protected_conditional:Npnn \mountain_replace_once:nnn #1 #2 #3 { T, F, TF }
{ \__mountain_replace_aux:Nnnn \c_false_bool {#1} {#2} {#3} }
\prg_new_protected_conditional:Npnn \mountain_replace_all:nnn #1 #2 #3 { T, F, TF }
{ \__mountain_replace_aux:Nnnn \c_true_bool {#1} {#2} {#3} }
\cs_new_protected:Npn \__mountain_replace_aux:Nnnn #1 #2 #3 #4
{
\ior_open:NnTF \l__mountain_replace_ior {#2}
{ \__mountain_replace_line:Nnnn #1 {#3} {#4} {#2} }
{
\msg_error:nnn { mountain } { file-not-found } {#2}
\prg_return_false:
}
}
\cs_new_protected:Npn \__mountain_replace_line:Nnnn #1 #2 #3 #4
{
\seq_clear:N \l__mountain_file_seq
\bool_set_false:N \l__mountain_replaced_bool
\ior_str_map_inline:Nn \l__mountain_replace_ior
{
\str_if_eq:nnTF {##1} {#2}
{
\bool_set_true:N \l__mountain_replaced_bool
\seq_put_right:Nn \l__mountain_file_seq {#3}
\bool_if:NF #1
{ \ior_map_break:n { \__mountain_replace_skip: } }
}
{ \seq_put_right:Nn \l__mountain_file_seq {##1} }
}
\__mountain_replace_end:n {#4}
}
\cs_new_protected:Npn \__mountain_replace_skip:
{
\ior_str_map_inline:Nn \l__mountain_replace_ior
{ \seq_put_right:Nn \l__mountain_file_seq {##1} }
}
\cs_new_protected:Npn \__mountain_replace_end:n #1
{
\ior_close:N \l__mountain_replace_ior
\iow_open:Nn \l__mountain_replace_iow {#1}
\seq_map_inline:Nn \l__mountain_file_seq
{ \iow_now:Nn \l__mountain_replace_iow {##1} }
\iow_close:N \l__mountain_replace_iow
\bool_if:NTF \l__mountain_replaced_bool
{ \prg_return_true: }
{ \prg_return_false: }
}
\msg_new:nnn { mountain } { file-not-found }
{ File~`#1'~not~found. }
\ExplSyntaxOff
\begin{document}
\newwrite\tempfile
\immediate\openout\tempfile=lists.tex
\immediate\write\tempfile{line1}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\write\tempfile{}
\immediate\write\tempfile{line2}
\immediate\closeout\tempfile
\replacelineonce{lists.tex}{line2}{line replaced}
{Replaced once:}
{Nothing replaced:}
\input{lists}
\bigskip
\replacelineall{lists.tex}{line2}{line replaced}
{Replaced all:}
{Nothing replaced:}
\input{lists}
\bigskip
\replacelineonce{lists.tex}{line2}{line replaced}
{Replaced once:}
{Nothing replaced:}
\input{lists}
\bigskip
\end{document}
答案2
如果需要进行更改,最好将其保存在 TeX 中。这会生成一个列表宏而不是写入文件,然后排版内容,写入一个文件,然后应用更改并再次排版,然后写入第二个文件。
因此排版输出是
lists.tex
写为
line1
line2
并lists2.tex
写为
line1
line 2 changed
来自 tex 文件:
\documentclass{scrartcl}
\newwrite\tempfile
\def\foo{}
\def\addline#1#2{\edef#1{\unexpanded\expandafter{#1\\{#2}}}}
\begin{document}
\addline\foo{line1}
\addline\foo{}
\addline\foo{line2}
{\def\\#1{#1 }\foo}% typeset it, was \input
{\def\\#1{#1^^J}
\immediate\openout\tempfile=lists.tex
\immediate\write\tempfile{\foo}
} % write first version
\immediate\closeout\tempfile
\def\\#1{%
\ifnum\pdfstrcmp{#1}{line2}=0
\unexpanded{\\{line 2 changed}}%
\else
\unexpanded{\\{#1}}%
\fi
}
\edef\foo{\foo} % apply the change
{\def\\#1{#1 }\foo}% typeset new version
{\def\\#1{#1^^J}
\immediate\openout\tempfile=lists2.tex
\immediate\write\tempfile{\foo}
} % write new version
\immediate\closeout\tempfile
\end{document}