使用 xparse 混合值和键/值

使用 xparse 混合值和键/值

先前的问题我改用了xparse。现在我陷入了兼容性陷阱,并试图同时允许新旧内容。起源是臭名昭著的宏,带有两个可选参数。我的最小示例是:

\documentclass{minimal}

\usepackage{xparse}

\NewDocumentCommand \sidenotetext { o o m } {%
(#1), (#2), #3
}%

\begin{document}
\sidenotetext{arg} % case (1)

\sidenotetext[1]{arg} % \sidenotetext[mark=1]{arg}; case 2

\sidenotetext[][]{arg} % case 3

\sidenotetext[][2]{arg} %\sidenotetext[offset=2]{arg}; case 4

\sidenotetext[3][]{arg} %\sidenotetext[mark=3]{arg}; case 5

\sidenotetext[4][5]{arg} %\sidenotetext[mark=4,offset=5]{arg}; case 6 
\end{document}

是否可以同时使左侧和右侧宏(注释掉)工作?如果不行,是否可以使情况 2 工作,即没有键始终表示标记,其余为键值?我认为,l3keys 是与 xparse 配合良好的正确选择?

答案1

如果两个可选参数处理的参数类型不兼容,则唯一可行的方法是将一个参数放在强制参数之前,将一个参数放在强制参数之后,因此

\NewDocumentCommand{\sidenotetext} { o m o }
 {%
  \IfNoValueTF{#1}...
 }

或者

\NewDocumentCommand{\sidenotetext} { O{default} m O{default} }
 {%
  ...
 }

通过这种方式你可以调用

\sidenotetext{text}
\sidenotetext[1]{text}
\sidenotetext{text}[2]
\sidenotetext[1]{text}[2]

但是这种方法不太好用。最好采用键值方法。

\ExplSyntaxOn
\NewDocumentCommand{\sidenotetext}{ O{} m }
 {
  \group_begin:
  \andy_sidenotetext:nn { #1 } { #2 }
  \group_end:
 }

\keys_define:nn { andy/sidenote }
 {
  mark .tl_set:N = \l_andy_sidenote_mark_tl,
  offset .tl_set:N = \l_andy_sidenote_offset_tl,
  offset .initial:n = 0,
 }

\cs_new_protected:Npn \andy_sidenotetext:nn #1 #2
 {
  \keys_set:nn { andy/sidenote } { #1 }
  <code using \l_andy_sidenote_mark_tl, \l_andy_sidenote_offset_tl
   and #2 (the actual text)>
 }
\ExplSyntaxOff

我不建议让这两个调用相互兼容:坚持使用一种语法。有一些宏允许这两种方法,但这是因为它们是在键值方法不可行时定义的。一个例子是\section在 Koma-Script 类中,其中对键值语法的测试是基于是否=出现在可选参数中,这不是很可靠。

如果您想要重新定义旧命令,我建议使用不同的名称。

相关内容