我知道这是一个奇怪的问题。
我知道可以有选项,更准确地说是选项键,由字母组成,但似乎还可以有更多。一些选项键似乎在表单中附加了一个值,key=value
但我无法弄清楚的一般形式value
。
最后,我知道选项可以一次传递,中间用逗号分隔。这似乎表明键和值都不能包含逗号。此外,假设键和值中都不能有空格似乎也相当安全。
您能给我提供更具体的信息吗?我问这个问题是因为我在做解析器。(我知道乳胶解析器,...我一定是傻了)
答案1
哦,你来这里是为了兜风……
请注意,有不同的 key=value 包,每个包都有自己的特点,并且可能与基本语法略有不同。
通常的行为是:
list
将嵌套括号外的逗号拆分为下一个pair
- 将第一个等号拆分
pair
到任何嵌套括号之外- 如果有:使用等号前的内容作为
raw-key
,等号后的内容作为raw-value
- 如果没有:一切都是
raw-key
并使用default-value
(value
如果有,否则错误)
- 如果有:使用等号前的内容作为
- 对于和,从两端
raw-key
删除raw-value
空格,删除空格后,删除一组外括号(如果有),其结果是key
和value
- 调用并用作
key-code
其参数(如果已定义,则出错)。key
value
key-code
应用这些规则后,就可以输入包含逗号、等号、空格等的值,只要它们是 TeX 中的合法参数,基本上就可以任意输入。
请注意,大多数软件包(据我所知)在步骤 3 中仅从任一端删除一个空格(但由于 TeX 将多个连续的空格组合成一个空格,并忽略行首的空格,因此大多数情况下这都没问题)。
对于包和类选项,情况更加复杂,因为 LaTeX 中有两个并行的列表,大多数包仅支持该列表的旧版本,该版本经过了一些非常特殊的处理(括号外的每个空格都被删除,如果括号两边都有空格,这也可能删除括号,其余的所有内容都完全展开),新版本是与给定的列表完全相同的列表。然后这些列表将接受上面列出的解析。
请注意,尽管列表的内容必须在完全扩展后才能保留,但列表按原样使用这一事实可能会导致奇怪的边缘情况下出现问题,尽管包和类选项通常不应该有如此复杂的输入以至于这成为一个真正的问题。
使用新列表的包/实现(其他所有包均使用旧列表):
ltkeys
(LaTeX 内核)\ProcessKeyOptions
expkv-opt
scrbase
(KOMA 脚本的选项处理)
(我希望我没有忽略任何其他使用新列表的包)
现在让我们来看看例外情况(这很可能是不详尽的!我是根据记忆输入的,所以我可能会忘记一个例外,或者我给出的一些细节稍微不正确 - 留下评论或编辑这个答案来修复我犯的任何错误!):
expkv
(我是这本书的作者,因此它是此列表中的第一本):- 2.2:
expkv
没有真正的默认值,但是支持一些更通用的值:它区分给定值的键(称它们为Val-<key>
)和没有值的键(因此在括号外没有任何等号;称它们为NoVal-<key>
),并且两者可以具有完全不同的值key-code
(当然,在中NoVal-<key>
您可以调用key-code
同名的Val-<key>
提供默认值)。 - 此外,
expkv
它还支持一种称为 -notation 的语法exp
,该语法允许控制 和 的扩展和操作value
。key
在第 3 点和第 4 点之间,这可能会删除 周围的一组额外括号,但前提是找到扩展前缀。如果您对该语法感兴趣,key
请参阅包文档 ( )。texdoc expkv-bundle
- 2.2:
keyval
:- 2:如果有多个等号,则第二个等号及其后的所有内容都将从值中删除。
- 3:取决于两端是否真的有空格,
keyval
可能会剥去多组外括号。
xkeyval
:参见keyval
,但它可能会剥去更多组外括号。l3keys
/ltkeys
:- 2:如果任何嵌套括号外有多个等号,则会引发错误
- 3:它会删除 和 两端的所有空格,
raw-key
而raw-value
不仅仅是一个 - 此外,它还以类似于 Unix 文件系统树的结构来处理键,并
/
为此删除目录分隔符周围的空格
pgfkeys
: 看keyval
- 此外,它还以类似于 Unix 文件系统树的结构来处理键,并
/
为此删除目录分隔符周围的空格 - 它还有处理程序,以便对于以
/.expand once
真实键结尾的输入,其内容是该后缀之前的任何内容,并且该值被扩展一次(还有其他处理程序)。
- 此外,它还以类似于 Unix 文件系统树的结构来处理键,并
kvsetkeys
:- 2:它包含值中第一个等号后的所有等号,但如果它们不包含在嵌套括号中,则会删除它们周围的空格。
options
:参见pgfkeys
(但它的处理程序有不同的名称,而且在处理文件树状结构的方式上也有细微的差别,恕我直言)simplekv
:- 2:如果有多个等号,则第二个等号及其后的所有内容都将从值中删除。
- 4:它不会在未定义时抛出错误
key-code
,而是定义一个新密钥保存value
(可通过访问\useKV
)
yax
:- 从哪里开始?的
yax
语法与上面描述的语法完全不同,但可以设置为也适用于上面的语法描述。 - 3:如果使用“标准 key=value 语法”,它可能会删除多组外括号,但我不知道它在这方面如何使用自己的语法。
- 从哪里开始?的
ltxkeys
:- 与现代 LaTeX 不兼容(并且可以说从来都不兼容)。
- 3:它不会去除任何外部支架。
luakeys
:- 对此并不确定,它不会解析 TeX 内部的键,而是使用 LuaTeX 内部的 Lua 来完成这项工作,说实话,我从未深入研究过它。
并且还有更多的 key=value 包,其中一些建立在上述包之上(最值得注意的是keyval
),不知道它们会引入哪些进一步的例外。
答案2
首先,我提到了 TeX 的基本原理。源文本的行被转换为一系列标记。标记处理器按照以下规则转换行:(粗略地说,仅当类别代码按常规设置时):
\foo
(控制序列)被转换为单个标记,%
结束阅读该行,从下一行开始阅读,- 行尾转换为空格,并将行组合为单个数据流,
- 多个连续空格转换为单个空格,
- 控制序列之外的空格和字符被转换为单个标记(一个字符就是一个具有给定类别的标记)。
还有一条重要的 TeX 规则:如果 TeX 解释标记序列的一部分(将其保存为宏主体、将其读取为参数等),则该部分始终平衡的文本即全部{
必须与 匹配}
。部分标记序列abc{def
或abc}def
永远不可能。这意味着扫描的key
或value
必须始终是平衡的文本。
还有另一条后续 TeX 规则:如果{...}
扫描表单中的参数,则在使用该参数之前删除这些外括号。
当使用逗号分隔符或等号分隔符分隔具有 key=value 语法的 token 序列时,它们必须位于{
and的外层}
,否则将无法遵守上述规则。因此,token 序列a{b,}cd,ef
被逗号分隔为两个序列a{b,c}d
和ef
。而 token 序列{ab,cd},ef
被逗号分隔并解释为ab,cd
和ef
。根据上述规则,外层括号将被删除。
最后但并非最不重要的 TeX 规则:标记\foo
在扩展过程中被转换为不同的东西(如果它是可扩展的控制序列)或者它们是特殊 TeX 语法规则的一部分,并且它们可以运行内部 TeX 算法。
以上所有规则都是通用的 TeX 规则,它们不由 LaTeX 宏集声明。
另一个答案中提到了各种 LaTeX 包使用的用于扫描 key=value 语法的更多语法规则。我又加了一个“包”。它不是一个真正的包,它是用于扫描 key=vaule 语法的 OpTeX 宏的一部分。
当 OpTeX 读取具有 key=value 语法的标记序列时,它会用逗号替换所有外部逗号+空格和空格+逗号,并用外部逗号分割文本。此外,它会用 替换所有外部+=
空格和空格+ 。如果分割部分包含外部,则 位于第一个外部之前,位于其之后。否则只有。宏程序员可以扩展或取消扩展与给定 相关的,可以测试给定的 是否已声明,并且可以为所有提到的键分配一个代码,为其他键分配另一个代码。扫描 key=value 语法时会处理此代码。=
=
=
key
=
value
key
value
key
key
请注意,OpTeX 中的所有 key=value 宏都仅位于 OpTeX 宏中的 16 行代码中。