为了以安全且可控的方式从大型 LaTeX 文件中提取文本,我让 LaTeX 本身写入文本文件。为了保留和调整一些格式信息和结构元素,我为文件提供了一个新标题,并在其中重新定义了用于此特殊目的的命令。这很好用,直到我需要带有可选参数的命令为止。
newfile
为了方便使用:
\documentclass{minimal}
\usepackage{newfile}
\newoutputstream{out}
\openoutputfile{out.text}{out}
\newcommand{\standardexample}[3]{#1:#2(#3)}
\newcommand{\optionalexample}[3][default]{#1:#2(#3)}
\begin{document}
text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}
\addtostream{out}{
text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}
}
\closeoutputstream{out}
\end{document}
我明白了
text 1:2(3) 而不是 default:2(3) 或 default:2(3)
在 pdf 中如预期的那样,但是
text 1:2(3) 和 \optionalexample[非默认]{2}{3} 或 \optionalexample{2}{3}
在文本文件中,日志中没有错误。
测试不使用newfile
,例如
\documentclass{minimal}
\newcommand{\standardexample}[3]{#1:#2(#3)}
\newcommand{\optionalexample}[3][default]{#1:#2(#3)}
\newwrite\tempfile
\begin{document}
\immediate\openout\tempfile=\jobname.tmp
\immediate\write\tempfile{text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}}
\immediate\closeout\tempfile
text \standardexample{1}{2}{3} and \optionalexample[not default]{2}{3} or \optionalexample{2}{3}
\end{document}
排版被一些错误消息打断了(其中一些甚至包含在 tmp 文件中),但我真的无法理解它们。
无论是扩展还是解决方法都很好。
答案1
使用可选参数定义的命令会自动增强,但这意味着它们能够存活下来\protected@write
;它们肯定不会\write
因为保护机制而存活下来。
这主要取决于你想写入辅助文件的内容;如果你需要扩张对于这些命令,您就没那么幸运了,因为它们必须执行分配才能生成替换文本。
使用\protected@write
如下输入
\protected@write\tempfile{}{\optionalexample[not default]{2}{3} or \optionalexample{2}{3}}
会写
text \optionalexample [not default]{2}{3} or \optionalexample {2}{3}
您可以\immediate
在以下位置找到版本将 \\ 写入文件
如果您需要命令的完整扩展,您可以使用xparse
:
\usepackage{xparse}
\DeclareExpandableDocumentCommand{\optionalexample}{O{default}mm}{#1:#2(#3)}
并且这将在 中起作用\immediate\write
。
\newcommand
您可以找到一些关于使用以下方法定义的带有可选参数的宏的讨论\newcommand[.][.]{.} 定义的命令是否强大?
你可以看到,\optionalexample
当 TeX 扩展你的宏时,它变成了
\@protected@testopt \optionalexample \\optionalexample {default}
现在问题开始了:当你执行 时,的\immediate\write
值为(这反过来意味着,但这并不相关。这是 的定义:\protect
\@typeset@protect
\relax
\@protected@testopt
% latex.ltx, line 619:
\def\@protected@testopt#1{%%
\ifx\protect\@typeset@protect
\expandafter\@testopt
\else
\@x@protect#1%
\fi}
在这种情况下,条件返回 true,因此 TeX 将显示
\@testopt \optionalexample \\optionalexample {default}
做什么\@testopt
?如下:
% latex.ltx, line 617:
\long\def\@testopt#1#2{%
\kernel@ifnextchar[{#1}{#1[{#2}]}}
这就是罪魁祸首!在\write
宏扩展期间,只执行宏扩展,而不执行赋值,因此\kernel@ifnextchar
无法工作,因为它是\futurelet
为了扫描以下标记而执行的。