我一直在尝试使用xparse
类似 Markdown 语法的自定义文档宏包。例如,我以前写过\cut{x}{P}{Q}
来生成。借助xparse
,我想改为写\cut(x)(P | Q)
-- 我发现这种类似 Markdown 的语法在文档源代码中更容易阅读。
(如果您不相信其好处,也可以将\send{y,x'}{x}{y,x'}{P}{Q}
其与\send (y,x')(x<y,x'> | P | Q)
作为生产手段进行比较。)
我当前用来定义的代码\cut
是:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\cut}{r() >{\SplitArgument{1}{|}}r()}{%
(\nu #1)(\use_i:nn#2 \mid \use_ii:nn#2)%
}
\ExplSyntaxOff
\begin{document}
Example 1: $\cut(x)(P | Q)$ % Works great!
% Example 2: $\cut(x)(P | \cut(y)(Q_1 | Q_2))$ % Fails with error
Example 3: $\cut(x)(P | {\cut(y)(Q_1 | Q_2)})$ % Works, but slightly annoying
\end{document}
当\cut
s 不嵌套时(如上面的示例 1 所示),一切都运行正常。但是,有时我需要嵌套\cut
s(如上面的示例 2 所示)。不幸的是,我收到一条xparse/split-excess-tokens
错误:“尝试拆分参数时标记过多|
。”
问题:有没有办法在拆分参数时强制xparse
将其r()
视为组以避免此错误?或者,我可以通过设置某些选项来关闭或将此错误减少为警告xparse
?
当然,我可以自己显式地添加一个组(如上面的示例 3 所示),但这有点烦人。另一种折衷方法是将第二个参数设为-type\cut
参数m
并写入\cut(x){P | \cut(y){Q_1 | Q_2}}
,但如果可能的话,我宁愿避免这样做。
答案1
解析参数时,xparse
非常努力地允许[
...]
或(
...以与...)
相同的方式工作,而无需更改类别代码。但是,当您想要对材料进行后处理时,这一点存在限制。输入{
}
\cut(x)(P | \cut(y)(Q_1 | Q_2))
\cut
只有在我们“知道”正在将(
...)
变成参数分组对时,才能正确解析该参数
P | \cut(y)(Q_1 | Q_2)
当您添加额外的括号时,这种方法是可行的,因为它有效地隐藏了|
解析步骤中的第二个括号,但如果没有括号,我们就需要评估所有参数以找到它实际结束的位置,或者做出任意选择,即“查找”每个命令的定义以允许嵌套解析。这不是 TeX(宏扩展系统)的工作方式,对其进行编程将极其困难,而且几乎肯定不可靠。(更改...xparse
的类别代码是一种可行的方法,但这需要重新标记材料以处理嵌套参数,而这总是有风险的,而且不是 100% 可靠的,所以我不推荐它。)(
)
正如 Werner 所言,你可以做的只是在第一个 处进行拆分|
,忽略其他任何 。例如
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Npn \SplitOnce #1#2
{
\cs_set_protected:Npn \tmp:w ##1 #1 ##2 \q_stop
{ \tl_set:Nn \ProcessedArgument { {##1} {##2} } }
\tmp:w #2 \q_stop
}
\NewDocumentCommand{\cut}{r() >{\SplitOnce{|}}r()}{%
(\nu #1)(\use_i:nn#2 \mid \use_ii:nn#2)%
}
\ExplSyntaxOff
\begin{document}
Example 1: $\cut(x)(P | Q)$
Example 2: $\cut(x)(P | \cut(y)(Q_1 | Q_2))$
Example 3: $\cut(x)(P | {\cut(y)(Q_1 | Q_2)})$
\end{document}
应该涵盖这一点。