gdef 与@ifnextchar

gdef 与@ifnextchar

我正在尝试创建一个带有两个或三个参数的命令,从而创建一个新命令。

在我的类文件中我有:

\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}定义\foox, y, bar;并\foobar{x}{y}{z}定义\foox, 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}

相关内容