] 位于可选参数内

] 位于可选参数内

我无意中发现(这里) 中用以分隔的可选参数内的右方括号[ ]可能会导致问题。

以下是说明该问题的示例代码:

\documentclass{article}


\begin{document}

\tableofcontents

\section[Square brackets ([ and ])]{Square brackets: [ and ]}
% bad: the TOC now has "Square brackets ([ and", and the actual title is a mere ")".

Some text.

\section[{Square brackets ([ and ])}]{Square brackets: [ and ]}
% good (works as originally intended)

Some text.

\end{document}

用作可选(以及非可选)参数的文本包含],并且此字符不应该用作可选参数终止符,而是用作匹配的方括号/圆括号。也许这是应该的,但问题是如何最好地规避任何潜在问题。将其括在一个组中可以工作,但我不知道这样做是否有其他副作用(也许在这里不是,\section但希望其他人有更好的例子说明分组可能导致问题)。除了写之外没有(明显的)方法,[{ }]因为[]通常不被转义。这[]是普通字符并承担句法功能(作为可选参数分隔符)会造成这种潜在的问题情况。

简单地将整个可选参数括在一个组 ( { }) 中是一个好的解决方案吗?还有其他/更好的方法吗?

答案1

LaTeX 的可选参数,即 TeX 的宏参数(分隔和非分隔)

LaTeX 中可选参数(即可以使用或不使用的参数)的概念是不是TeX 的解析和执行直接支持。TeX 宏总是期望具有相同数量的参数,并使用相同的语法来界定参数。

LaTeX 中的可选参数是通过从没有参数的宏开始实现的,首先预查下一个标记是什么(例如寻找 a[或 a *),然后内部调用一个可以准确解析这样的 a[*并期望它存在的 TeX 宏。

对于 TeX 解析器,只有两种类型的宏参数:“无界”和“有界”参数。“无界”参数的正常情况定义如下:

\def\test#1#2#3{... do something with #1 #2 #3}

最多可以有 9 个参数(即,此外还可以有#4... )。#9

如果在参数说明符之前或之后放置任何内容,#<digit>那么我们就处于“分隔”参数的情况,例如,

\def\test*#1[#2]#3foo{... do something with #1 #2 #3}

此处,第二个参数\test应被and*包围,第三个参数后必须跟字符串。但这里没有任何“可选”的东西,这些组件现在始终是必需的,如果不是,则会产生低级 TeX 错误,要么是“使用的不符合其定义”,要么是“参数失控”。[]foo\test

TeX 的参数解析规则

TeX 中的括号(或者更准确地说是 catcode 为 1 和 2 的字符,通常是开括号和闭括号)在解析宏的参数时起着特殊作用。TeX 在解析参数时会跟踪它们,以确保它们是平衡的。

如果你有一个带有无分隔参数的宏,例如,

\def\test#1{\def\result{#1}}

然后 TeX 的解析器在执行时执行以下操作\test

  • 如果之后的第一个标记\test不是 catcode 为 1 的字符(通常{),那么下一个标记就成为参数。
  • 否则,它会进一步扫描并仅查看 catcode,直到看到 catcode 为 1 和 2 的标记数量相等,换句话说,一组平衡的大括号组。
  • 然后它会剥去外部的标记集,剩余的材料将成为参数。换句话说(在正常的 TeX catcode 生效的情况下),参数周围的括号不会成为参数的一部分。但是,里面的任何其他括号都会保留下来。

例子:

\test{A}      \show\result
\test{{A}}   \show\result

这现在给出了

> \result=macro:
->A.
l.4 \test{A}      \show\result

? 
> \result=macro:
->{A}.
l.5 \test{{A}}   \show\result

即外面的括号消失了。

TeX 仅针对 catcode 为 1 和 2 的标记执行上述操作。如果您使用分隔参数的概念(带有其他 catcode 的字符),则不会发生平衡。例如

\def\test[#1]{\def\result{#1}}

Now\test是一个宏,它期望后面跟着一个[,并且它的参数在解析下一个时(通常)结束]。在参数内部,TeX 仍然需要 catcode 1 和 2 的匹配标记,但它不关心括号:只要没有任何 catcode 1 的标记没有匹配的 catcode 2 的标记,第一个括号就会结束参数。

因此,执行时会发生以下情况\test

  • TeX 期望一个[,如果不是,则会抱怨
  • 然后,它开始解析参数,寻找]同一括号级别上的下一个参数(或者更确切地说,在同一级别上,匹配具有 catcode 1 和 2 的标记)。
  • 一旦发现,]其间的任何东西都将成为参数,界定参数的标记将被丢弃。
  • 但是,最后一句话并不完全正确:当看到结束分隔符时,实际发生的情况如下:TeX 移动到与在无分隔符情况下找到参数结尾时相同的状态。这意味着它现在查看候选参数,如果它以 catcode 1 标记开头并以 catcode 2 标记结尾,它将同时删除这两个标记。

使用上述定义的例子:

\test[A]     \show\result
\test[{A}]   \show\result

这次我们得到:

> \result=macro:
->A.
l.10 \test[A]     \show\result

? 
> \result=macro:
->A.
l.11 \test[{A}]   \show\result

因此,总而言之,括号组(或者更确切地说是 catcode 1 和 2 标记组)是向 TeX 扫描仪隐藏某些内容的方法,否则这些内容将被误解。如果您确实希望将可选参数括在一组括号中(在解析后),则需要编写[{{...}}]

现在你可能想知道为什么 LaTeX 没有分别制作[catcode ]1 和 2 的标记。答案是:

  • 它们将无法在普通文本中使用
  • 更重要的是 TeX 扫描仪只查看 catcodes,因此你可以将其混合搭配,{一切]都将是一样的

例子:

\def\test#1{\def\result{#1}}

\catcode`\[=1
\catcode`\]=2

\test{[{A]}]     \show\result

这可行并给出:

> \result=macro:
->[{A]}.
l.8 \test{[{A]}]     \show\result

LaTeX2e 可选参数的结论

总而言之,人们可以声称 LaTeX 中的可选参数确实正确地指定为[{(open) 和}](close),并且[...]如果您不必向扫描仪隐藏任何内容(大多数情况下都是如此),这只是一种方便的快捷方式。这样做不会产生任何副作用(只要使用序列 --- 当然,如果您在参数中间使用括号,则它们不会被剥离,并且会产生副作用)。

实际上,莱斯利恰恰相反:他说,[...]界定可选参数,以防遇到麻烦,请使用[{...}]

xparse通过包在 LaTeX3 中提供可选参数

xparse使用的实现包具有expl3更精细的扫描器,并且能够正确处理可选参数内的嵌套括号,即通常不需要将其向扫描器隐藏。

例子:

\documentclass{article}
\usepackage{xparse}

\DeclareDocumentCommand\test{om}{\def\result{#1||#2}}

\test{A} \show\result
\test[B]{A} \show\result
\test[B and [C]]{A} \show\result

执行此代码时,我们得到以下结果:

> \result=macro:
->-NoValue-||A.
l.6 \test{A} \show\result

? 
> \result=macro:
->B||A.
l.7 \test[B]{A} \show\result

? 
> \result=macro:
->B and [C]||A.
l.8 \test[B and [C]]{A} \show\result

当然,这仅在括号匹配时才有用,例如,在\test[B] and C]]{A}扫描仪无法弄清楚您指的B] and C]是可选参数的内容而不仅仅是的情况下B。因此,在这种情况下,仍然需要使用[{...}]来隐藏不平衡的材料。

相关内容