我有一个非常简单的命令,其中一个参数可以包含逗号,在这种情况下,输出可能不易阅读,因为它使用的文本可能包含其他逗号,从而使得该符号的结束位置不明显。
不幸的是,我经常忘记用括号把这个参数括起来,因此造成混淆。
我如何重新定义该命令,以便它的所有出现都产生美观的输出(即恰好使用一对括号如果它包含逗号)?
具体命令为:
\newcommand{\SubSeq}[3][\empty]{{#2 \upharpoonright #3}^{#1}}
可能包含逗号的参数是#3
。
编辑:我不太关心更复杂的情况,例如(a,b),c,d
,您可以假设输入要么有括号围绕整个参数,要么没有任何括号。
然而,我同意理想的解决方案我希望每次参数中的分隔符外面有逗号时都加上括号。(并且您绝对可以假设分隔符是匹配的)
感谢所有贡献答案的人!我决定接受 Qrrbrbirlbel 的答案,因为这是实现我想要的功能的最简单的解决方案,但我真的感谢你们所有人。
答案1
代码
\documentclass[varwidth]{standalone}
\usepackage{amsmath,amssymb,xstring}
\newcommand{\SubSeq}[3][]{%
{#2 \upharpoonright
\IfSubStr{#3}{,}{%
\IfBeginWith{#3}{(}{%
\IfEndWith{#3}{)}{#3}{(#3)}%
}{(#3)}%
}{#3}}%
\if\relax\detokenize{#1}\relax\else^{#1}\fi}
\begin{document}
$ \SubSeq{a}{b} $ \par
$ \SubSeq{a}{c, d} $ \par
$ \SubSeq{a}{(e, f)} $ \par
$ \SubSeq{a}{(g, h), i} $ \par
$ \SubSeq{a}{((j, k), l)} $ \par
$ \SubSeq{a}{[m, n]} $ \par
$ \SubSeq{a}{(o, p), (q, r)} $ \par
\end{document}
输出
答案2
这样可以避免添加额外的括号,即使材料位于方括号或其他分隔符内。
\documentclass{article}
\makeatletter
\newcommand{\AddParenMaybe}[1]{\@addparen@ #1\@addparen@ }
\def\@addparen@ #1#2\@addparen@ {\in@{#1}{\left([<\{}% add more if necessary
\ifin@\expandafter\@thirdofthree
\else\expandafter\@firstofone
\fi
{\in@{,}{#1#2}%
\ifin@\expandafter\@firstoftwo
\else\expandafter\@secondoftwo
\fi}%
{(#1#2)}{#1#2}}
\makeatother
\begin{document}\thispagestyle{empty}
$
\AddParenMaybe{b} \quad
\AddParenMaybe{c,d} \quad
\AddParenMaybe{(c,d)} \quad
\AddParenMaybe{X^{X^X},d} \quad
\AddParenMaybe{\left(X^{X^X},d\right)} \quad
$
\end{document}
答案3
根据背景,这可能比 Qrrbrbirlbel 的答案更令人生畏,也可能不那么令人生畏。;-)
但先检查是否有左括号,然后再检查是否有逗号,这样比较容易。
\documentclass{article}
\usepackage{amsmath,amssymb,xparse}
\ExplSyntaxOn
\NewDocumentCommand{\SubSeq}{o m m}
{
\bakuriu_subseq:nn {#2}{#3}
\IfValueT{#1}{^{#1}}
}
\cs_new_protected:Npn \bakuriu_subseq:nn #1 #2
{
#1 \upharpoonright \nolinebreak
\tl_if_in:nnTF { #2 } { ( }
{ #2 } % there is ( so we do nothing
{ % there is no (, check if a comma is present
\tl_if_in:nnTF { #2 } { , }
{ (#2) }
{ #2 }
}
}
\ExplSyntaxOff
\begin{document}
$
\SubSeq{a}{b} \quad
\SubSeq{b}{c,d} \quad
\SubSeq[3]{f}{(g,h)}
$
\end{document}
下面的扩展不必太认真对待。;-)
\documentclass{article}
\usepackage{amsmath,amssymb,xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\SubSeq}{o m m}
{
\bakuriu_subseq:nn {#2}{#3}
\IfValueT{#1}{^{#1}}
}
\cs_new_protected:Npn \bakuriu_subseq:nn #1 #2
{
#1 \upharpoonright \nolinebreak
\tl_if_in:nnTF { #2 } { , }
% there is a comma, so we do a more complicated check
{ \bakuriu_check_parens:n { #2 } }
% no comma, print the argument as is
{ #2 }
}
\cs_new_protected:Npn \bakuriu_check_parens:n #1
{
\regex_match:nnTF { \A \( .* \) \Z } { #1 }
% we have parentheses at start and end
{
\regex_match:nnTF { \A \( .* (\(|\)) .* \) \Z } { #1 }
% we have parentheses inside, add a pair of braces
{
% check for unbalanced parentheses if we remove the first
\regex_match:nnTF { \A \( (.*?\(.*?\).*).* \) } { #1 }
{ #1 }
{ ( #1 ) }
}
% no inner parentheses
{ #1 }
}
% no outer parentheses
{ ( #1 ) }
}
\ExplSyntaxOff
\begin{document}
$
\SubSeq{a}{b} \quad
\SubSeq{b}{c,d} \quad
\SubSeq[3]{f}{(g,h)}
$
$
\SubSeq{a}{(b,c)}\quad
\SubSeq{a}{(b,c),d}
$
$
\SubSeq{a}{(b,c),(d,e)}\quad
\SubSeq{a}{((b,c),(d,e))}
$
$
\SubSeq[2]{a}{(b,c),d,(e,f)}
$
$
\SubSeq{a}{a,(b,c),e}\quad
\SubSeq{a}{(a,(b,c),e)}
$
$
\SubSeq{a}{a,(b,(c,d)),e}\quad
\SubSeq{a}{(a,(b,(c,d)),e)}
$
\end{document}
人们可以允许不同的内部定界符,首先用合适的正则表达式替换将它们规范化为括号,这留作练习。;-)
答案4
感谢 David 的辛勤工作,我可以给出他的答案的一个版本,该版本不使用计数寄存器。相反,它只是让 TeX 计算嵌套:
\documentclass{article}
\usepackage{amssymb}
\makeatletter
\newcommand*\SubSeq[3][\empty]{%
{#2 \upharpoonright \sbox0{$\zz#3\zzg$}\zzp(#3\zzp)}^{#1}%
}
\def\zzdef#1{%
\mathcode`#1"8000\begingroup
\lccode`~`#1%
\lowercase{\endgroup\def~}%
}
\def\zz{%
\zzdef\,{\let\zzp\relax}%
\zzdef\({\begingroup}%
\zzdef\){\endgroup}%
\let\zzp\@gobble
}
\def\zzg{%
\global\let\zzp\zzp
}
\makeatother
\begin{document}
$\SubSeq{a}{(g,h),(i,k)}$
$\SubSeq{a}{b} \quad
\SubSeq{a}{c,d} \quad
\SubSeq[3]{f}{(g,h)}$
$\SubSeq{a}{(b,c)} \quad
\SubSeq{a}{(b,c),d}$
$\SubSeq{a}{(b,c),(d,e)} \quad
\SubSeq{a}{((b,c),(d,e))}$
$\SubSeq[2]{a}{(b,c),d,(e,f)}$
$\SubSeq{a}{a,(b,c),e}\quad
\SubSeq{a}{(a,(b,c),e)}$
$\SubSeq{a}{a,(b,(c,d)),e} \quad
\SubSeq{a}{(a,(b,(c,d)),e)}$
\end{document}
输出是一样的。