我正在向文件写入几行,但我发现强健的命令会损坏写入的文件。在这种情况下,\plural
命令可能很脆弱,但在实际应用中,它必须是强健的。MWE:
\documentclass{article}
\usepackage{xifthen}
\immediate\newwrite\txtfile
\immediate\openout\txtfile=\jobname.txt
\DeclareRobustCommand{\plural}[3]{\ifthenelse{\equal{#1}{1}}{#2}{#3}}
\newcommand{\woman}[1]{#1 \plural{#1}{woman}{women}}
\begin{document}
\immediate\write\txtfile{\woman{1}}
\immediate\write\txtfile{\woman{2}}
\end{document}
我想要一种方法,让文本文件显示“1 名女性”,并在下一行显示“2 名女性”,定义\plural
为强健。
答案1
如果将文本写入文件,则只有 TeX 语言的一个子集可用。可扩展机制正在运行,但分配和其他不可扩展的内容却无法运行。
在这种情况下\plural
可以扩展:
\documentclass{article}
\immediate\newwrite\txtfile
\immediate\openout\txtfile=\jobname.txt
\makeatletter
\newcommand*{\plural}[1]{%
\ifnum#1=1 %
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\makeatother
\newcommand*{\woman}[1]{#1 \plural{#1}{woman}{women}}
\begin{document}
\immediate\write\txtfile{\woman{1}}
\immediate\write\txtfile{\woman{2}}
\end{document}
结果:
1 woman
2 women
评论:
- 因为
\plural
它是完全可扩展的,所以它已经很强大了,\DeclareRobustCommand
不需要。 - 比较是通过可扩展的
\ifnum
、\ifthenelse
不可扩展的来完成的。
答案2
\write
当参数包含应受“保护”或用 定义的宏时,不应使用\DeclareRobustCommand
。\protected@immediatewrite
可以使用 的定义\protected@write
作为模型来定义宏:
\documentclass{article}
\usepackage{xifthen}
\immediate\newwrite\txtfile
\immediate\openout\txtfile=\jobname.txt
\makeatletter
\long\def\protected@immediatewrite#1#2#3{%
\begingroup
\let\thepage\relax
#2%
\let\protect\@unexpandable@protect
\edef\reserved@a{\immediate\write#1{#3}}%
\reserved@a
\endgroup
\if@nobreak\ifvmode\nobreak\fi\fi
}
\newcommand\lazowrite[1]{\protected@immediatewrite\txtfile{}{#1}}
\makeatother
\DeclareRobustCommand{\plural}[3]{\ifthenelse{\equal{#1}{1}}{#2}{#3}}
\newcommand{\woman}[1]{#1 \plural{#1}{woman}{women}}
\begin{document}
\lazowrite{\woman{1}}
\lazowrite{\woman{2}}
\end{document}
这\lazowrite
只是语法糖\protected@immediatewrite
。
如果你打算使用\nofiles
,你应该添加
\makeatletter
\g@addto@macro\nofiles{%
\long\def\protected@immediatewrite#1#2#3{%
\immediate\write\m@ne{}\if@nobreak\ifvmode\nobreak\fi\fi
}%
}
\makeatother
前\documentclass
。
LaTeX3 的实现;使用\int_case:nnF
命令可以更加灵活,以可扩展的方式允许多种情况。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% allocate a write stream
\iow_new:N \g_lazo_output_iow
\iow_open:Nn \g_lazo_output_iow { \c_job_name_tl .txt }
% User interface
\DeclareExpandableDocumentCommand{\plural}{mmm}
{
\lazo_plural:nnn { #1 } { #2 } { #3 }
}
% Inner function
\cs_new:Npn \lazo_plural:nnn #1 #2 #3
{
\int_case:nnF { #1 }
{ { 1 }{ #2 } }
{ #3 }
}
% User interface
\NewDocumentCommand{\lazowrite}{m}
{
\lazo_write:n { #1 }
}
% Inner function
\cs_new_protected:Npn \lazo_write:n #1
{
\iow_now:Nx \g_lazo_output_iow { #1 }
}
\ExplSyntaxOff
\newcommand{\woman}[1]{#1 \plural{#1}{woman}{women}}
\begin{document}
\lazowrite{\woman{1}}
\lazowrite{\woman{2}}
\end{document}