宏中的括号行为

宏中的括号行为

我正在学习使用宏来定义具有可变数量参数的命令(以下)。我看到了一种在我看来出乎意料的行为。如果\newcommand有一个包含表达式的括号,则宏的行为将不正常。以下是代码和三个示例,一个具有预期的行为,另一个带有括号,还有一个(我的真实用例),我在其中使用了\marginpar

\documentclass{article}
\usepackage[utf8]{inputenc}
\makeatletter
\newcommand{\checknextarg}{\@ifnextchar\bgroup{\gobblenextarg}{.}}
\newcommand{\gobblenextarg}[1]{ and #1\@ifnextchar\bgroup{\gobblenextarg}{.}}

\newcommand{\shoppinglist}[1]{%
    Shopping list: #1\checknextarg}
\newcommand{\shoppinglistbrace}[1]{%
    {Shopping list: #1\checknextarg}}
\newcommand{\shoppinglistmargin}[1]{%
    \marginpar{\par\noindent{\rule{\marginparwidth}{0.4pt}} Shopping list #1\checknextarg}}
\makeatother

\begin{document}
\shoppinglist{T1}{T2}\par
\shoppinglistbrace{T1}{T2}\par
\shoppinglistmargin{T1}{T2}
\end{document}

结果图片

答案1

首先:具有可变数量参数的命令是邪恶的

现在一个明显的问题是:在\shoppinglistbrace\shoppinglistmargin\checknextarg在错误的地方,因为它所做的只是看到}接下来的。

撇开最后一个命令,它需要不同的处理:

\documentclass{article}

\makeatletter
\newcommand{\checknextarg}{\@ifnextchar\bgroup{\gobblenextarg}{.}}
\newcommand{\gobblenextarg}[1]{ and #1\checknextarg}

\newcommand{\shoppinglist}[1]{%
    Shopping list: #1\checknextarg}
\newcommand{\shoppinglistbrace}[1]{%
    {Shopping list: #1}\checknextarg}
%\newcommand{\shoppinglistmargin}[1]{%
%    \marginpar{\rule{\marginparwidth}{0.4pt} Shopping list #1}%
%    \checknextarg}
\makeatother

\begin{document}
\shoppinglist{T1}{T2}

\shoppinglistbrace{T1}{T2}

%\shoppinglistmargin{T1}{T2}

\end{document}

在此处输入图片描述

最后一个呢?您需要先收集参数,然后将它们传递给\marginpar

\documentclass{article}

\makeatletter
\newcommand{\checknextarg}{\@ifnextchar\bgroup{\gobblenextarg}{.}}
\newcommand{\gobblenextarg}[1]{ and #1\checknextarg}

\newcommand{\checknextargmp}{\@ifnextchar\bgroup\addnextarg\finishmp}

\newcommand{\shoppinglist}[1]{%
    Shopping list: #1\checknextarg}

\newcommand{\shoppinglistmargin}{%
   \def\shopping@list{\rule{\marginparwidth}{0.4pt} Shopping list }% initialize
   \checknextargmp}
\newcommand{\addnextarg}[1]{%
   \expandafter\def\expandafter\shopping@list\expandafter{\shopping@list and #1 }%
   \checknextargmp}
\newcommand{\finishmp}{
   \marginpar{\raggedright\shopping@list.}%
}
\makeatother

\begin{document}

\shoppinglist{T1}{T2}

\shoppinglistmargin{T1}{T2}

\end{document}

在此处输入图片描述

当然还有更好的策略。

\documentclass{article}

\ExplSyntaxOn

\NewDocumentCommand{\shoppinglist}{m}
 {
  \axll_shoppinglist:n { #1 }
 }

\NewDocumentCommand{\shoppinglistmargin}{m}
 {
  \marginpar
   {
    \raggedright
    \rule{\marginparwidth}{0.4pt}~
    \axll_shoppinglist:n { #1 }
   }
 }

\cs_new:Nn \axll_shoppinglist:n
 {
  Shopping~list:~\clist_use:nnnn { #1 } { ~and~ } { ,~ } { ~and~ }
 }

\ExplSyntaxOff

\begin{document}

\shoppinglist{T1}

\shoppinglist{T1,T2}

\shoppinglist{T1,T2,T3}

\shoppinglistmargin{T1}

\shoppinglistmargin{T1,T2}

\shoppinglistmargin{T1,T2,T3}

\end{document}

在此处输入图片描述

相关内容