在 xparse 中将 \SplitArgument 与 r() 参数结合使用

在 xparse 中将 \SplitArgument 与 r() 参数结合使用

我一直在尝试使用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}

\cuts 不嵌套时(如上面的示例 1 所示),一切都运行正常。但是,有时我需要嵌套\cuts(如上面的示例 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}

应该涵盖这一点。

相关内容