\@for 循环中的括号

\@for 循环中的括号

在编写宏以使用循环来操作列表项时 \@for,我发现括号内的项的行为会根据它们是否有前导空格而有所不同:

\documentclass{article}
\usepackage[T1]{fontenc}

\begin{document}
\makeatletter

\def\uselist#1{%
  \@for\temp:=#1\do{\meaning\temp\par}}

\verb|\listwithcommas{Lima,Alpha,{Delta,Oscar},Tango,{Whisky,Echo,Romeo},Xray}|

\def\listwithcommas{Lima,Alpha,{Delta,Oscar},Tango,{Whisky,Echo,Romeo},Xray}
\uselist{\listwithcommas}


\verb|\listwithcommasandspaces{ {Lima}, Alpha, {Delta,Oscar}, Tango, {Whisky,Echo,Romeo}, Xray}|

\def\listwithcommasandspaces{ {Lima}, Alpha, {Delta,Oscar}, Tango, {Whisky,Echo,Romeo}, Xray}
\uselist{\listwithcommasandspaces}


\end{document}

我想在应用宏后保留括号,因为当项目前面有空格时。是否可以在循环内执行此操作\@for?目的是,无论列表是如何提供的(通过宏),输出列表都将保留括号。也就是说,和都\listwithcommas应该\listwithcommasandspaces给出第二个输出。

另一个问题是为什么有空格和没有空格时行为会不同。

在此处输入图片描述

编辑

这里有一个例子来阐明意图。

假设我有一个宏\subtractlist,并且使用了两次。首先我Lima从列表中减去,然后{Delta,Oscar}从结果列表中减去。由于第一次使用后我丢失了括号,因此第二次使用将不起作用。

我可以将新形成的列表的所有项目括在括号中。在这种情况下,它可以与 一起使用,\listwithcommas但不能与 一起使用\listwithcommasandspaces,因为有双括号和空格。

\documentclass{article}
\usepackage[T1]{fontenc}

\begin{document}
\makeatletter

\def\listwithcommas{{Lima},Alpha,{Delta,Oscar},Tango,{Whisky,Echo,Romeo},Xray}

\def\listwithcommasandspaces{ {Lima}, Alpha, {Delta,Oscar}, Tango, {Whisky,Echo,Romeo}, Xray}

\newif\if@isinlist
\def\subtractlist#1#2{% #1:original list, #2:remove list
  \gdef\@subtractlist{}%
  \@for\@tempa:=#1\do{%
    \@isinlistfalse%
    \@for\@tempb:=#2\do{\ifx\@tempa\@tempb\@isinlisttrue\fi}%
      \if@isinlist%
        \else%
          \ifx\@subtractlist\empty%
              \expandafter\gdef%
              \expandafter\@subtractlist%
%             \expandafter{\@tempa}%
%%% extra pair of braces added
              \expandafter{\expandafter{\@tempa}}%
            \else%
              \expandafter\g@addto@macro%
              \expandafter\@subtractlist%
%             \expandafter{\expandafter,\@tempa}%
%%% extra pair of braces added
              \expandafter{\expandafter,\expandafter{\@tempa}}%
          \fi%
      \fi%
    }%
  \let\currentlist\@subtractlist}

\def\removelista{Bravo,Lima}
\def\removelistb{Bravo,{Delta,Oscar}}


\subtractlist{\listwithcommas}{\removelista}
\verb|subtract Lima:| \meaning\currentlist

\subtractlist{\currentlist}{\removelistb}
\verb|subtract {Delta,Oscar}:|\meaning\currentlist

\bigskip

\subtractlist{\listwithcommasandspaces}{\removelista}
\verb|subtract Lima:| \meaning\currentlist

\subtractlist{\currentlist}{\removelistb}
\verb|subtract {Delta,Oscar}:|\meaning\currentlist

\end{document}

无需额外的括号:

在此处输入图片描述

加上额外的括号:

在此处输入图片描述

答案1

\@for非常小,因此在删除或保留括号和空格方面不会太费劲。括号是作为 TeX 参数抓取的一部分被删除的,因此您必须添加额外的安全性才能保留它们。我\@empty在每个项目前面添加了一个,这样 TeX 就不会删除括号,然后我\@empty在将项目传递给 之前将其展开以删除它\uselistcmd

在此处输入图片描述

\documentclass{article}
\usepackage[T1]{fontenc}

\begin{document}

\makeatletter
\def\q@stop{\q@stop}
\def\uselist#1{\expandafter\uselist@\expandafter\@empty#1,\q@stop,}
\def\uselist@#1,{\expandafter\uselist@@\expandafter{#1}}%
\def\uselist@@#1{%
  \ifx\q@stop#1\else
    \uselistcmd{#1}%
    \expandafter\uselist@\expandafter\@empty
  \fi}
\makeatother

\def\uselistcmd#1{\detokenize{(#1)}\par}

\verb|\listwithcommas{Lima,Alpha,{Delta,Oscar},Tango,{Whisky,Echo,Romeo},Xray}|

\def\listwithcommas{Lima,Alpha,{Delta,Oscar},Tango,{Whisky,Echo,Romeo},Xray}
\uselist{\listwithcommas}


\verb|\listwithcommasandspaces{ {Lima}, Alpha, {Delta,Oscar}, Tango, {Whisky,Echo,Romeo}, Xray}|

\def\listwithcommasandspaces{ {Lima}, Alpha, {Delta,Oscar}, Tango, {Whisky,Echo,Romeo}, Xray}
\uselist{\listwithcommasandspaces}

\end{document}

答案2

如果仔细查看输出,您会发现输出中包含一个空格,而\temp第一组的值并不是这个空格。

在第一种情况下,TeX 会将逗号之前的所有内容解析为要消化的参数。这里会丢弃括号,因为它传递的是文字参数,例如,{Lima}它会将其视为单个参数并删除括号,就像将参数传递给括号内的宏一样。

但是在空格版本中,传入的不再是{Lima}但是{Lima}(空格不会被丢弃,因为的扩展\@for将在被消化的参数之间插入非字母标记\@for。现在参数是空格加上一个组,因此它保留括号,因为它们不再位于外层并且可以丢弃。

可以按照你的意愿做(毕竟 TeX 是图灵完备的),但这并不简单。将列表中的每个项目括在括号中,并将要保留的项目用双括号括起来即可。或者,你可以添加空格,然后从得到的项目中解析出它们。标记列表可能可以实现一些奇特的功能。

相关内容