本站的许多人都知道(也许觉得有点烦人)我会尝试使用我的stackengine
软件包解决任何 LaTeX 问题。我的座右铭就像隔夜快递服务一样:“如果堆放得当,我们就发货”。
我在该包的一个解析例程中发现了一个奇怪的问题,我知道它与主题或健壮性非常相关(我对此有一定的理论理解,但肯定还不够了解如何克服)。令我惊讶的是,这个特定问题仅在\centering
我发现相当奇怪和出乎意料的调用之后出现。
我把问题归结为这个 MWE。在这里,\@readMANYrows
将接受一个由多行数据组成的参数,每行由“行尾”(EOL) 字符分隔,并将其解析为单独的行数据。stackengine
由于历史原因,该包默认将此 EOL 字符设置为空格,但有一个包选项可以使 EOL\\
更符合 LaTeX 用户的期望(我意识到\\
这是一个宏,而不是一个字符,这也许是这个问题的根源)。
当 EOL 设置为 时\\
,一切都会正常工作。\centering
但是,如果调用 ,则只有当 EOL 不是 时,该例程才会起作用\\
。最后,如果我设置\protect\\
EOL,即使居中,一切也会恢复正常,但最后一种语法确实很麻烦,仅用于学术目的。
所以我的问题是双重的:我很好奇它是如何\centering
破坏解析例程的(它不像\centering
是我例程的一个参数......它不是)?并且,有没有一种简单的方法可以使解析例程变得健壮,而不需要,例如,用 LaTeX3 重写它,就像 egreg 在解析行(`\\`)和制表符(`&`)?
我只想补充一点,这并\usepackage{fixltx2e}
不能解决这个问题。
\documentclass{article}
\usepackage{ifthen}
\newcounter{ROWcellindex@}
\makeatletter
\newcommand\setstackEOL[1]{%
\ifthenelse{\equal{#1}{}}{\def\SEP@char{ }}{\def\SEP@char{#1}}%
\expandafter\define@processROW\expandafter{\SEP@char}%
}
\newcommand\define@processROW[1]{%
\def\@processROW##1#1##2||{%
\protected@edef\@preSEP{##1}%
\protected@edef\@postSEP{##2}%
}%
}
% FOR PROCESSING A GROUP OF STACK ROWS SEPARATED BY \SEP@char
\newcommand\@readMANYrows[1]{%
\def\@doneROWreads{F}%
\def\@postSEP{#1\SEP@char}%
\setcounter{ROWcellindex@}{0}%
\whiledo{\equal{\@doneROWreads}{F}}{%
\stepcounter{ROWcellindex@}%
\expandafter\@processROW\@postSEP||%
\ifthenelse{\equal{\@postSEP}{}}{%
\def\@doneROWreads{T}%
}{}%
\ifthenelse{\equal{\SEP@char}{ }}%
{\def\@preSEPtemp{\@preSEP}}%
{\def\@preSEPtemp{\ignorespaces\@preSEP\unskip}}%
\expandafter\protected@edef\csname arg\roman{ROWcellindex@}\endcsname{%
\@preSEPtemp}%
}%
% \narg GIVES HOW MANY ROWS WERE PROCESSED
\xdef\narg{\arabic{ROWcellindex@}}%
}
\begin{document}
% OK IF NO CENTERING
\setstackEOL{\\}
\@readMANYrows{a \\ b \\ c}
\argi, \argii, \argiii\\
% OK IF DIFFERENT EOL CHARACTER
\centering
\setstackEOL{$}
\@readMANYrows{d $ e $ f}
\argi, \argii, \argiii\\
% BREAKS! \\ NOT ROBUST
%\centering
%\setstackEOL{\\}
%\@readMANYrows{g \\ h \\ i}
%\argi, \argii, \argiii\\
% PROTECTING \\ WORKS, BUT IS A NUISANCE TO USE
\centering
\setstackEOL{\protect\\}
\@readMANYrows{j \protect\\ k \protect\\ l}
\argi, \argii, \argiii\\
\end{document}
答案1
使用 执行的重新定义\centering
也会\ifthenelse{\equal{\\}{}}{true}{false}
失败,因为\equal
执行完全扩展。这对默认定义没有影响,因为它是用 完成的\DeclareRobustCommand
。当然,您也应该\protected@edef
尽可能避免。
最好使用更强大、更可靠的测试。我会选择 LaTeX3,但etoolbox
它也有很多有用的功能。
下面是一个实现etoolbox
。
\documentclass{article}
\usepackage{etoolbox}
\newcounter{ROWcellindex@}
\newtoggle{@doneROWreads}
\makeatletter
\newcommand\setstackEOL[1]{%
\ifstrempty{#1}{\def\SEP@char{ }}{\def\SEP@char{#1}}%
\expandafter\define@processROW\expandafter{\SEP@char}%
}
\newcommand\define@processROW[1]{%
\def\@processROW##1#1##2||{%
\def\@preSEP{##1}%
\def\@postSEP{##2}%
}%
}
% FOR PROCESSING A GROUP OF STACK ROWS SEPARATED BY \SEP@char
\newcommand\@readMANYrows[1]{%
\togglefalse{@doneROWreads}%
\edef\@postSEP{\unexpanded{#1}\expandonce{\SEP@char}}%
\setcounter{ROWcellindex@}{0}%
\whileboolexpr{test {\nottoggle{@doneROWreads}}}{%
\stepcounter{ROWcellindex@}%
\expandafter\@processROW\@postSEP||%
\expandafter\ifstrempty\expandafter{\@postSEP}{%
\toggletrue{@doneROWreads}%
}{}%
\expandafter\ifstrequal\expandafter{\SEP@char}{ }%
{}%
{\edef\@preSEP{\ignorespaces\expandonce{\@preSEP}\unskip}}%
\csedef{arg\roman{ROWcellindex@}}{\expandonce{\@preSEP}}%
}%
% \narg GIVES HOW MANY ROWS WERE PROCESSED
\xdef\narg{\arabic{ROWcellindex@}}%
}
\begin{document}
% OK IF NO CENTERING
\setstackEOL{\\}
\@readMANYrows{a \\ b \\ c}
\argi, \argii, \argiii
% OK IF DIFFERENT EOL CHARACTER
\centering
\setstackEOL{$}
\@readMANYrows{d $ e $ f}
\argi, \argii, \argiii\\
% BREAKS! \\ NOT ROBUST
\centering
\setstackEOL{\\}
\@readMANYrows{g \\ h \\ i}
\argi, \argii, \argiii
% PROTECTING \\ WORKS, BUT IS A NUISANCE TO USE
\centering
\setstackEOL{\protect\\}
\@readMANYrows{j \protect\\ k \protect\\ l}
\argi, \argii, \argiii
\end{document}