我正在尝试定义一个具有可变参数数量的宏。例如,我想定义一个具有两个参数的宏,该宏也可以使用一个参数。因此,同一个宏可以以两种方式工作。
\textcolor{red}{sample text}
这会将红色限制在示例文本中,而只需调用\textcolor{red}
即可将红色一直打开到文档末尾。因此,使用宏的第二种方法是
\textcolor{red}
我尝试使用 来实现宏\@ifnextchar
。但并没有取得太大成功。您能给我一些提示吗?
根据@Joseph 的建议,我修改了我的玩具代码,它运行正常。我仍然无法理解代码中的实际执行流程。这是我的代码。
\documentclass[12pt]{article}
\makeatletter
\def\oneortwoargs#1{%
\@ifnextchar\bgroup%
{\twoargs@aux{#1}}
{\onearg@only{#1}}
}
\def\onearg@only#1{%
Only argument provided: #1 %
}
\def\twoargs@aux#1#2{%
Two arguments are provided. \\%
First argument: #1 \\ %
Second argument: #2%
}
\makeatother
\begin{document}
\oneortwoargs{gg}{fff}
\oneortwoargs{qq}
\end{document}
正如@Joseph 在下面解释的那样,输入流中只剩下一个标记。令我困惑的是\onearg@only
和\twoargs@aux
以相同的方式调用,并且只有一个参数。
答案1
我会用xparse
包来执行此操作,因为所有内容都是“预先打包的”:
\documentclass{article}
\usepackage{color,xparse}
\NewDocumentCommand\MyTextColor{m+g}{%
\IfNoValueTF{#2}
{\color{#1}}
{\textcolor{#1}{#2}}%
}
\begin{document}
\MyTextColor{green}{stuff}
\MyTextColor{red} Some text
\end{document}
当然也可以使用\@ifnextchar
\documentclass{article}
\usepackage{color}
\makeatletter
\newcommand*\MyTextColor[1]{%
\@ifnextchar\bgroup
{\textcolor{#1}}
{\color{#1}}%
}
\makeatother
\begin{document}
\MyTextColor{green}{stuff}
\MyTextColor{red} Some text
\end{document}
关键点是您需要寻找{
使用\bgroup
而不是尝试直接使用它(因为它是 begin-group 字符)。
为了解释该\@ifnextchar
部分如何处理需要 1 个或 2 个参数的情况,我的第二种方法是
\newcommand*\MyTextColor[1]{%
定义一个吸收的宏一论点。所以:
\MyTextColor{red}{stuff}
吸收red
并#1
留{stuff}
在输入流中,而
\MyTextColor{red} other stuff
也吸收red
并#1
留other stuff
在输入流中。我们现在应用\@ifnextchar
,它“偷看”下一个标记不吸收. 测试内容
\@ifnextchar\bgroup
{\textcolor{#1}}
{\color{#1}}%
因此,根据结果,要么\textcolor{red}
要么\color{red}
被插入到输入流中。因此,我们最终得到
\textcolor{red}{stuff}
或者
\color{red} other stuff
这意味着\textcolor
将获取所需的两个参数,而\color
只获取一个参数。关键是{red}
是重新插入\textcolor
在或之后输入\color
。
虽然与问题没有直接关系,但对该xparse
方法的一些注释可能会有用。使用该xparse
包时,参数用字母描述,m
表示强制参数,g
用 表示可选参数,用大括号 (IE一个可选的 TeX 组)。+
字母前面的 A 允许该参数接受段落标记,因此在我的定义中,第一个参数不能(它应该是一个颜色的名称),而第二个参数可以(它是任意文本)。
如果可选参数根本不存在,则参数将返回一个特殊标记 ( )。如果需要默认值,我会使用。g
同样的方法适用于标准 LaTeX 可选参数,它们表示为或,具体取决于是否需要默认值。我已经使用测试;和进行了测试。\NoValue
G{<default>}
o
O
\NoValue
\IfNoValueTF
\IfNoValueT
\IfNoValueT
答案2
在 ConTeXt 中,你可以使用 定义这样的宏\dodoublegroupempty
。例如:
\def\TwoArgMacro
{\dodoublegroupempty\doTwoArgMacro}
\def\doTwoArgMacro#1#2%
{\ifsecondargument
Two arguments were passed: #1 and #2
\else
One argument was passed: #1
\fi}
其工作原理是检查下一个字符是否等于\bgroup
。