我正在尝试创建一个带有两个或三个参数的命令,从而创建一个新命令。
在我的类文件中我有:
\def\foobar#1#2{\gdef\foo{#1, #2, \@ifnextchar\bgroup{foo}{bar}}}
如果我调用\foobar{X}{Y}
,\foo
则会生成X, Y, foo
,但是如果我调用,\foobar{X}{Y}{Z}
我会得到Missing \begin{document}.
而不是X, Y, barZ
。
不使用 gdef 也可以工作:
\def\baz#1#2{#1, #2, \@ifnextchar\bgroup{foo}{bar}}
答案1
\def\foobar#1#2{%
\@ifnextchar\bgroup
{\gdef\foo{#1, #2, foo}}
{\gdef\foo{#1, #2, bar}}%
}
您需要将其放在\@ifnextchar
正确的位置。但这仍然不能满足您的要求。这是一个选项,\foobar{x}{y}
定义\foo
为x, y, bar
;并\foobar{x}{y}{z}
定义\foo
为x, y, z
。
\def\foobar#1#2{%
\@ifnextchar\bgroup
{\foobaraux{#1}{#2}}
{\foobaraux{#1}{#2}{bar}}%
}
\def\foobaraux#1#2#3{%
\gdef\foo{#1, #2, #3}%
}
使用 xparse 可能会更简洁
\usepackage{xparse}
\NewDocumentCommand \foobar { m m g }
{%
\IfValueTF {#3}
{\gdef\foo{#1,#2,#3}}
{\gdef\foo{#1,#2,bar}}%
}
尽管经典语法带有可选参数\foobar{x}{y}[optional]
。
答案2
在类文件中您有:
\def\foobar#1#2{\gdef\foo{#1, #2, \@ifnextchar\bgroup{foo}{bar}}}
为什么要使用\def
而不是\newcommand
?
不管怎样。根据该定义,\foobar
无论如何都会处理两个参数来定义宏\foo
。\foobar
只会定义但不会调用/使用/执行/扩展宏\foo
。因此,无论如何
使用都不会导致排版任何内容。\foobar
\foobar{X}{Y}
\foo
全局定义要扩展为的宏:
X, Y, \@ifnextchar\bgroup{foo}{bar}
。
如果{Z}
在对 的调用后面附加\foobar{X}{Y}
(使得输入看起来像
\foobar{X}{Y}{Z}
),则定义\foo
以相同的方式进行:\foobar
仍然只处理两个参数,即参数{X}
和{Y}
,用于定义\foo
-macro 而不尝试排版任何内容。然后处理\foobar
-macro 完成。然后 (La)TeX 将在输入流中找到{Z}
尚未处理的标记序列,因为它不构成 的\foobar
参数之一,并且 (La)TeX 将尝试排版该标记序列。当这种排版尝试发生在文档的前言中,在 之前时,会导致错误消息\begin{document}
。
顺便一提:
始终关注事情执行的时间。
例如,有一个“定义时间”,还有一个“扩展时间”。
按照您的尝试,\@ifnextchar
在定义 -macro 时不会发生 -forking 。每次扩展/执行 -macro\foo
时都会发生这种情况。\foo
也许\@ifnextchar
在定义时进行 -forking\foo
更接近您想要的:
\newcommand\foobar[2]{%
\@ifnextchar\bgroup%
{\foobarhelper{#1}{#2}{bar}}%
{\foobarhelper{#1}{#2}{foo}{}}%
}%
\newcommand\foobarhelper[4]{\gdef\foo{#1, #2, #3#4}}
例如,如果在序言中你有
\foobar{X}{Y}%
\begin{document}
,得出:
\@ifnextchar\bgroup%
{\foobarhelper{X}{Y}{bar}}%
{\foobarhelper{X}{Y}{foo}{}}%
\begin{document}
-check\@ifnextchar
将发现\begin
-token 的含义不等于 token 的含义\bgroup
,因此该检查将保持不变,
\foobarhelper{X}{Y}{foo}{}
同时保留\begin
-token 及其后面的所有内容:
\foobarhelper{X}{Y}{foo}{}%
\begin{document}
该序列\foobarhelper{X}{Y}{foo}{}
依次得出 --\foobarhelper
的第四个参数为空 --
\gdef\foo{X, Y, foo}
:
\gdef\foo{X, Y, foo}
\begin{document}
例如,如果在序言中你有
\foobar{X}{Y}{Z}%
\begin{document}
,得出:
\@ifnextchar\bgroup%
{\foobarhelper{X}{Y}{bar}}%
{\foobarhelper{X}{Y}{foo}{}}%
{Z}%
\begin{document}
-check\@ifnextchar
将发现序列中左括号的含义{Z}
确实与标记的含义相同\bgroup
,因此该检查将进行
\foobarhelper{X}{Y}{bar}
,同时保留左括号和其后面的所有内容:
\foobarhelper{X}{Y}{bar}%
{Z}%
\begin{document}
该序列\foobarhelper{X}{Y}{bar}{Z}
依次产生
\gdef\foo{X, Y, barZ}
:
\gdef\foo{X, Y, barZ}
\begin{document}