因此,我尝试实现一个应该支持以下语法的COOL
-style宏:\Sum
\Sum{\ldots} % -> \sum \ldots
\Sum[i]{\ldots} % -> \sum_{i} \ldots
\Sum[i \in I]{\ldots} % -> \sum_{i \in I} \ldots
\Sum[i, 0, N]{\ldots} % -> \sum_{i=0}^{N} \ldots
\Sum[{i,j}, 0, N]{\ldots} % -> \sum_{i,j=0}^{N} \ldots
\Sum[{i,j,k}]{\ldots} % -> \sum_{i,j,k} \ldots
重要的是,我希望使用括号保护第一个参数中的逗号。实际的实现是在expl3
用户界面中使用xparse
。不幸的是,xparse
如果括号包围了整个参数,则似乎总是会删除参数中的括号,因此无论我的内部代码做什么,这种保护都不会在所有情况下都起作用。查看文档,我找不到阻止这种情况的方法。
我尝试了表单的宏签名
\DeclareDocumentCommand \Sum { s >{ \SplitArgument{2}{,} } o m }
{ ... }
\DeclareDocumentCommand \Sum { s o m }
{ ... }
我是不是漏掉了什么?有没有一种(未记录的)方法可以让 xparse 不去掉这些括号,而只需绕过 xparse 并手动实现接口(也许使用参数处理器?)?如果没有,这是否需要在 latex github 上提交错误报告/功能请求?
答案1
您可以通过在左括号后插入另一个标记(如果有的话)来解决这个问题(如答案中的概念证明)。\Wisperwind_Sum_original_code:nnn
用原始代码替换以排版总和(包括使用 处理可选星号\IfBooleanTF
)。
\documentclass[]{article}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l_Wisperwind_clist
\NewDocumentCommand \Sum { s t[ }
{
\IfBooleanTF { #2 }
{ \Sum_two { #1 } [ \use_none:n {} }
{ \Sum_two { #1 } }
}
\NewDocumentCommand \Sum_two { m O{ \use_none:n {} } m }
{
\Wisperwind_Sum_original_code:non { #1 } { #2 } { #3 }
}
\cs_new:Npn \Wisperwind_Sum_original_code:nnn #1 #2 #3
{
\sum
\clist_set:Nn \l_Wisperwind_clist { #2 }
\int_case:nn { \clist_count:N \l_Wisperwind_clist }
{
{ 1 } { \sb { \clist_item:Nn \l_Wisperwind_clist { \c_one_int } } }
{ 2 }
{
\sb { \clist_item:Nn \l_Wisperwind_clist { \c_one_int } }
\sp { \clist_item:Nn \l_Wisperwind_clist { 2 } }
}
{ 3 }
{
\sb
{
\clist_item:Nn \l_Wisperwind_clist { \c_one_int }
=
\clist_item:Nn \l_Wisperwind_clist { 2 }
}
\sp { \clist_item:Nn \l_Wisperwind_clist { 3 } }
}
}
#3
}
\cs_generate_variant:Nn \Wisperwind_Sum_original_code:nnn { non }
\ExplSyntaxOff
\begin{document}
$\Sum{\ldots}$ % -> \sum \ldots
$\Sum[i]{\ldots}$ % -> \sum_{i} \ldots
$\Sum[i \in I]{\ldots}$ % -> \sum_{i \in I} \ldots
$\Sum[i, 0, N]{\ldots}$ % -> \sum_{i=0}^{N} \ldots
$\Sum[{i,j}, 0, N]{\ldots}$ % -> \sum_{i,j=0}^{N} \ldots
$\Sum[{i,j,k}]{\ldots}$ % -> \sum_{i,j,k} \ldots
\end{document}
答案2
这里使用 LaTeX2e(有关 Plain TeX 请参见下文):
\documentclass{article}
\usepackage{listofitems}
\makeatletter
\newcommand\Sum{\@ifnextchar[{\Sumaux[\@gobble}{\sum}}
\makeatother
\def\Sumaux[#1]#2{
\sum
\setsepchar{,}
\readlist\sumargs{#1}
\ifnum\listlen\sumargs[]>1\relax
_{\sumargs[1]=\sumargs[2]}
\ifnum\listlen\sumargs[]>2\relax^\sumargs[3]\fi
\else
_{\sumargs[1]}
\fi
#2
}
\begin{document}
\[\Sum{\ldots} \]% -> \sum \ldots
\[\Sum[i]{\ldots} \]% -> \sum_{i} \ldots
\[\Sum[i \in I]{\ldots} \]% -> \sum_{i \in I} \ldots
\[\Sum[i, 0, N]{\ldots} \]% -> \sum_{i=0}^{N} \ldots
\[\Sum[{i,j}, 0, N]{\ldots} \]% -> \sum_{i,j=0}^{N} \ldots
\[\Sum[{i,j,k}]{\ldots} \]% -> \sum_{i,j,k} \ldots
\end{document}
这种方法也可以在 Plain TeX 中实现:
\input listofitems
\def\gobble#1{}
\def\Sum{\futurelet\next\doSum}
\def\doSum{\ifx[\next%
\expandafter\Sumaux\expandafter[\expandafter\gobble\else\sum\fi}
\def\Sumaux[#1]#2{
\sum
\setsepchar{,}
\readlist\sumargs{#1}
\ifnum\listlen\sumargs[]>1\relax
_{\sumargs[1]=\sumargs[2]}
\ifnum\listlen\sumargs[]>2\relax^\sumargs[3]\fi
\else
_{\sumargs[1]}
\fi
#2
}
$$\Sum{\dots} $$% -> \sum \ldots
$$\Sum[i]{\ldots} $$% -> \sum_{i} \ldots
$$\Sum[i \in I]{\ldots} $$% -> \sum_{i \in I} \ldots
$$\Sum[i, 0, N]{\ldots} $$% -> \sum_{i=0}^{N} \ldots
$$\Sum[{i,j}, 0, N]{\ldots} $$% -> \sum_{i,j=0}^{N} \ldots
$$\Sum[{i,j,k}]{\ldots} $$% -> \sum_{i,j,k} \ldots
\bye
答案3
括号的剥离是经过深思熟虑的,因为\newcommand
生成的命令需要括号来表示情况
\foo[{]}]{bar}
而xparse
- 生成的则不然。没有括号剥离,
\foo[{bar}]
和
\foo[bar]
可以区别对待。
在您的例子中,您有一个带有一个条目的逗号列表。显而易见的解决方案是提供第二个空条目
\Sum[{i,j},]{\ldots}
因为这是一个无操作。