我正在学习使用宏来定义具有可变数量参数的命令(以下这)。我看到了一种在我看来出乎意料的行为。如果\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}