如何在宏的参数之间允许空格

如何在宏的参数之间允许空格

例如,我会写\defpoint [option] (1,2) {A}而不是 \defpoint[option](1,2){A}。构建这种宏的最佳方法是什么?

只有参数 [...] 是可选的,如果参数之间允许有空格,则不需要空格(强制性的?)。

如果用户犯了一个语法错误,记录下来可能会很有趣,但是该怎么办呢?

答案1

使用标准 LaTeX2e 方法,无需额外努力即可实现此目的:

\makeatletter
\long\def\defpoint{%
  \@ifnextchar[%]
    {\defpoint@aux@i}
    {\defpoint@aux@i[]}%
}
\long\def\defpoint@aux@i[#1]{%
  \@ifnextchar(%)
    {\defpoint@aux@ii{#1}}
    {\ERROR}% As the ( ... ) part is not optional
}
\long\def\defpoint@aux@ii#1(#2)#3{\showtokens{#1:#2:#3}}
\makeatother
\defpoint [option] (1,2) {A}

这对于三个论点有三个不同的原因!

对于第一个参数(在方括号中),TeX 会跳过控制序列后的空格,程序员对此无能为力:这里始终允许使用空格(忽略相当尴尬的 catcode 技巧)。

对于括号中的可选参数,\@ifnextchar会故意跳过它拾取的任何空格,因此会忽略]和之间的任何空格(。可以创建一个\@ifnextchar不跳过空格的版本(实际上,这比当前实现更容易)。请注意,如果没有该参数,那么 TeX无论如何[...] 都会跳过后面的空格。\defpoint

最后,再次以标准方式抓取强制参数使用 TeX 的逻辑。如果不采取其他预防措施,#3这里将被抓取为下一个 <balanced text>,可以更简单地看到类似

\def\test#1#2#3{\showtokens{#1:#2:#3}}
\test {A} {B} {C}

答案2

xparse默认情况下允许这样做。请参阅章节1.2 间距和可选参数xparse文档

TeX 会查找函数名称后的第一个参数,而不考虑中间是否有空格。强制参数和可选参数都是如此。

除非某些特定的参数格式,这是一个最小的例子:

enter image description here

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\NewDocumentCommand{\mycmd}{o d() m}{%
  1: #1; 2: #2; 3: #3
}
\begin{document}
\mycmd[abc](ijk){xyz} \par
\mycmd [abc](ijk){xyz} \par
\mycmd[abc] (ijk){xyz} \par
\mycmd[abc](ijk) {xyz} \par
\mycmd  [abc] (ijk){xyz} \par
\mycmd[abc](ijk)    {xyz} \par
\mycmd[abc]         (ijk){xyz}
\end{document}

可以通过布尔测试对参数执行语法错误,例如\IfNoValueTF

答案3

除了其他答案之外,我想指出的是,使用 LaTeX 的标准宏定义机制,您可以准备选项,而不必将其余参数传递给辅助宏\defpoint@option

该宏\defpoint不使用下一个标记,而是将它们留在输入流中。如果没有选项,它只会在标记流的开头添加默认选项,然后调用\defpoint@option,这会使用所有参数。

\makeatletter
\newcommand\defpoint[1][option]{%
    \defpoint@option[#1]% partial application
}
\def\defpoint@option[#1](#2,#3) #4{% There _has_ to be a space before #4
    Look ma: #1, #2, #3, and #4.
}
\makeatother

\defpoint(1,2) {A}
\defpoint[blah](1,2) {A}
\defpoint(1,2){A} % doesn't work

相关内容