我有一个本地类,很多人都在使用。我希望它能做的一件事就是将各种用户定义的数据写入文件,以便后续的 LaTeX 文档可以执行不同的操作,但使用相同的用户定义参数。我对读取和写入外部文件还不太熟悉,所以我的问题可能比较简单。
下面是一个演示该问题的 MWE:
\documentclass{article}
\begin{document}
%% USER CONTROLS THIS DEFINITION
\def\userdef{abc} % Works Great
%\def\userdef{abc\\def} % Breaks \write
%% I CONTROL THE FOLLOWING
\def\userdefContent{\noexpand\def\noexpand\userdef{\userdef}}%
\newwrite\tempfile%
\immediate\openout\tempfile=userdata.tex
\immediate\write\tempfile{\userdefContent}
\immediate\closeout\tempfile
\end{document}
用户使用 定义一些已知变量\def
,我想将其写入文件,格式为用户定义它的\def\userdef{blah blah blah}
位置blah blah blah
。这样,我可以\input
将其写入另一个文件,并使用用户在第一轮中定义的相同数据对第二个文档进行预初始化。
问题是我想要编写的一些用户变量可能会填充\\
字符,这显然会破坏\write
。取消注释 MWE 中的一行以演示这一点。
我对解决方案很灵活。理想情况下,我希望我的输出文件包含
\def \userdef {abc\\def}
但我愿意接受
\def \userdef {abc*LINEFEED*def}
其中*LINEFEED*
是任意的字符串序列,用于提醒我稍后需要返回\\
。作为最后的手段,我甚至会选择
\def \userdef {abc def}
已被剥离的地方\\
。
我想,如果没有其他解决方案,我会指示用户群不要\\
在他们的宏中使用\def
我定义的其他宏(然后我可以在之前重新定义它们\write
)。但我认为他们可能会反对最后一种方法。我也会反对它,因为它会破坏与旧文档的向后兼容性。
如果有标准的 LaTeX 方式在不同文档之间传输数据,我也愿意接受完全不同的方法。我想补充一点,我有一个stringstings
解决方案,当\userdef
仅由 catcode 11 和 12 材料和字符组成时\\
,它可以工作,但我不能提前保证用户不会在他的 中粘贴其他一些宏\def
。
答案1
您必须\\
在写入时禁用扩展性。但一般来说,\write
当允许“自由”输入时会出现问题:\textbf
否则类似的命令肯定会中断。
最好构建一个“立即”版本\protected@write
:
\documentclass{article}
\usepackage{xpatch}
\makeatletter
% get a copy of `\protected@write
\let\protected@iwrite\protected@write
% patch the copy to add \immediate
\xpatchcmd{\protected@iwrite}{\write}{\immediate\write}{}{}
\makeatother
\newwrite\tempfile
\begin{document}
\def\userdef{abc\\def} % Breaks \write
\immediate\openout\tempfile=userdata.tex
\makeatletter
\protected@iwrite\tempfile{\let\\\relax}{\userdef}
\immediate\closeout\tempfile
\makeatother
\end{document}
请注意\protected@iwrite
,与其兄弟一样,它有第二个参数,可以在其中执行声明以更改写入范围的命令含义;在本例中,我将其设置\\
为等于,\relax
因此它变得不可扩展。如果没有这个,输出将是
abc\protect \\def
临时任务
abc\\def
如预期的。
一种可能的简化方法是使用与 LaTeX 相同的方法\typeout
(感谢 David Carlisle 的建议):
\documentclass{article}
\makeatletter
\def\protected@iwrite#1#2#3{%
\begingroup\set@display@protect
#2% local assignments
\immediate\write#1{#3}\endgroup}
\makeatother
\begin{document}
\def\userdef{abc\\\textbf{def}}
\immediate\openout\tempfile=userdata.tex
\makeatletter
\protected@iwrite\tempfile{}{\def\protect\userdef{\userdef}}
\immediate\closeout\tempfile
\makeatother
\end{document}
输出为\def\userdef{abc\\\textbf {def}}
。请注意 也是\textbf
可以的。\protect
当然,脆弱的命令需要 。