写入文件 - 强大的命令会弄乱写入的文本文件

写入文件 - 强大的命令会弄乱写入的文本文件

我正在向文件写入几行,但我发现强健的命令会损坏写入的文件。在这种情况下,\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}

相关内容