使用允许使用键值对的命令时,如何提供包含逗号的参数值?例如,假设我使用下面的包\newacronym
中的命令:glossaries
\newacronym[firstplural = Alphas, Bravos, and Charlies (ABCs), plural = ABCs]{ABC}{ABC}{Alpha, Bravo, Charlie}
不幸的是,逗号用于分隔键值对,因此该Bravos, and Charlies (ABCs)
部分无法正确解析。有办法解决这个问题吗?
答案1
这是 LaTeX 中一个相当常见的问题,因为 TeX 没有提供良好的工具来编写一个可靠的解析器,该解析器可以理解,
应该将列表中的两个项目分开的 which 和,
只是句子的一部分的 which 之间的区别。事实上,大多数编程语言都不会这样做,而是依靠其他东西来区分它们,比如将字符串包装在"
...中"
。
TeX 只有宏,以及获取这些宏的参数的奇怪方式。如果您使用 定义宏,\def\foo[#1]{<use #1>}
那么您必须使用\foo
,\foo[argument]
如果您省略其中一个[
,否则]
会发生一些不好的事情(“不好”是指错误或参数是意料之外的东西)。
定义:分隔参数是任何参数(#<number>
),后跟至少一个标记的某个序列(\def\bar#1\relax{}
、\def\foo[#1]{}
、\def\baz#1xyz{}
分别是宏的示例,其参数分别由\relax
、]
和xyz
分隔)。
宏的分隔参数将是分隔符第一次出现之前最短的括号平衡标记列表。也就是说,当扫描宏的分隔参数时,TeX 将跟踪沿途找到的{
和 的数量}
,并搜索与参数分隔符匹配的第一个标记序列,只要 的数量与}
的数量匹配{
。
此外,如果分隔参数以 开头{
并以 结尾}
,则外层括号将被删除。因此,如果您有一个宏,例如 ,\def\test[#1]{}
则使用 as\test[hello]
或\test[{hello}]
将获取相同的hello
参数。但是,如果参数恰好有一个]
,则使用\test[he[l]lo]
将仅获取he[l
as 参数,而使用\test[{he[l]lo}]
将获取he[l]lo
。
以下是TeXbook这解释了这一点(花点时间阅读;这一段特别稠密):
你可能会问,TeX 如何确定参数在何处结束。答案:有两种情况。分隔参数
<parameter text>
在到达参数文本的末尾或下一个参数标记之前,后面跟着一个或多个非参数标记;在这种情况下,相应的参数是具有正确嵌套组的最短(可能为空)标记序列{...}
,输入中后面跟着这个特定的非参数标记列表。(类别代码和字符代码必须匹配,控制序列名称必须相同。)未限定参数在 中紧接着<parameter text>
一个参数标记,或者它出现在参数文本的最末尾;在这种情况下,相应的参数是下一个非空白标记,除非该标记是“{
”,此时参数将是{...}
后面的整个组。在这两种情况下,如果以这种方式找到的参数具有“ ”的形式{<nested tokens>}
,其中<nested tokens>
代表任何正确嵌套在括号中的标记序列,则包围参数的最外层括号将被删除,并将保留<nested tokens>
。
(<parameter text>
是定义中宏名之后和之前的内容{
,例如\def\macro<parameter text>{<replacement text>}
,参数标记是 catcode-6(通常为#
)字符)
但这一切和你的问题有什么关系呢?
考虑这个非常简单的逗号分隔列表解析器:
% Define
\def\quarkstop{\quarkstop}
\def\csvparse#1{%
\csvparseloop#1,\quarkstop,}
\def\csvparseloop#1,{%
\ifx\quarkstop#1%
\else
\do{#1}%
\expandafter\csvparseloop
\fi}
% Use
\def\do#1{(#1)}
\csvparse{one,{two,2},three}
宏\csvparse
只是一个用户友好的界面,可以执行以下操作:
\csvparseloop one,{two,2},three,\quarkstop,
并且\quarkstop
存在,以便代码可以检测到列表的末尾。
该\csvparseloop
宏是一个带分隔符的宏(用 定义\def\csvparseloop#1,{...}
),其第一个(也是唯一的)参数由 分隔,
。因此,每次扩展时,它都会抓取所有内容直到下一个(括号平衡),
。
在第一次迭代中,将after\csvparseloop
视为参数并处理。 在第二次迭代中,由于列表不平衡,因此 after 被忽略,因此TeX 会抓取整个并删除括号,因此参数是,
one
one
,
{two
{
}
{two,2}
two,2
。
在第三次迭代中,参数为three
,在第四次迭代中,参数为\quarkstop
,因此循环结束。
在你的情况下,key-val 解析器的行为将或多或少类似于上面的示例,并且将理解每个键都由,
,并且无法区分,
用于分隔键值对的 和,
句子中间的 。这就是为什么您需要将值括在括号中,这样解析器就不会感到困惑。
当然,这不是大卫的错:-)
也可以看看: