提供命令键值参数,值中带有逗号

提供命令键值参数,值中带有逗号

使用允许使用键值对的命令时,如何提供包含逗号的参数值?例如,假设我使用下面的包\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[las 参数,而使用\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 会抓取整个并删除括号,因此参数是,oneone
,{two{}{two,2}two,2
在第三次迭代中,参数为three,在第四次迭代中,参数为\quarkstop,因此循环结束。

在你的情况下,key-val 解析器的行为将或多或少类似于上面的示例,并且将理解每个键都由,,并且无法区分,用于分隔键值对的 和,句子中间的 。这就是为什么您需要将值括在括号中,这样解析器就不会感到困惑。

当然,这不是大卫的错:-)


也可以看看:

相关内容