\centering 破坏了脆弱的命令(有修复方法吗?)

\centering 破坏了脆弱的命令(有修复方法吗?)

本站的许多人都知道(也许觉得有点烦人)我会尝试使用我的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}

在此处输入图片描述

相关内容