我想要一个可以接受 1、2 或 3 个参数的命令,并且针对每个参数数量执行不同的操作。
\c{a} -> C_a
\c{a}{b} -> C_{a}^{[b]}
\c{a}{b}{c} -> C_{a,c}^{[b]}
由于 Latex 没有命令重载,我认为可选参数就足够了:
\c{a} -> C_a
\c[b]{a} -> C_{a}^{[b]}
\c[c][b]{a} -> C_{a,c}^{[b]}
我找到这个很好的答案使用xparse
可能正是我需要的。但是他的答案仅适用于 2 个可选参数。他提到了如何将其扩展到任意数量的参数,但我不知道该怎么做。我试过:
\usepackage{xparse}
....
\DeclareDocumentCommand \c { o o m } {%
\IfNoValueTF {#1} {%
\IfNoValueTF {#2} {%
C_{#3}%
}{%
C_{#3}^{[#2]}%
}%
}{%
C_{#2, #3}^{[#1]}%
}%
}
$\c{a} \c[b]{a} \c[c][b]{a}$
但似乎我无法让带有两个参数的分支起作用:
我究竟做错了什么?
答案1
您应该从检查开始#2
而不是开始#1
,因为#2
只有有才会有值#1
。
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand \C { o o m } {%
\IfNoValueTF{#2}
{%
\IfNoValueTF {#1}
{%
C_{#3}%
}
{%
C_{#3}^{[#1]}%
}%
}
{%
C_{#3, #1}^{[#2]}%
}%
}
\begin{document}
$\C{a} \quad \C[b]{a} \quad \C[c][b]{a}$
\end{document}
和不用来\DeclareDocumentCommand
覆盖的含义\c
:当你必须引用某些名字中带有“ç”的法国或土耳其作家时,你会后悔的。
答案2
您希望定义一个宏\c
。但\c
已经在 LaTeX 中定义。
因此,我今后将不再将该宏称为\c
。
相反,我将将该宏称为\macroc
。
您是否知道在 TeX/LaTeX 中由单个标记组成的未限定参数不需要嵌套在括号中?
定义后\newcommand\foo[1]{This is argument 1: #1.}
,
\foo{b}
将产生与相同的结果
\foo b
。
定义之后\newcommand\bar[2]{This is argument 1: #1. This is argument 2: #2.}
,以下调用都会产生相同的结果:
\bar{a}{b}
\bar a{b}
\bar {a}b
\bar ab
\bar{a} {b}
\bar a {b}
\bar {a} b
\bar a b
这是因为
- 当未限定的参数由单个标记组成时,不需要括号。
- (La)TeX 确实会丢弃未限定参数前面的空格标记。
当被调用时 \macroc{a}{b}c
——如何\macroc
“知道”用户是否打算使用c
由\macroc
单个标记组成的第三个参数c
,或者用户是否打算\macroc
仅使用两个参数进行调用,即{a}
和{b}
而不应c
被视为第三个参数?
形势很不明朗。
\macroc
你可以通过只处理一个未限定的参数并\macroc
检查该参数是否属于其中一种模式,从而将情况变得明确
{⟨argument 1⟩}
{⟨argument 1⟩}{⟨argument 2⟩}
{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}
\macroc
如果检测到其中一种模式,则采取相应行动,\macroc
否则发出错误消息。
IE,
\macroc{{⟨argument 1⟩}}
\macroc{{⟨argument 1⟩}{⟨argument 2⟩}}
\macroc{{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}}
通过下面的例子,\macroc
处理一个未限定的参数。
句法:\macroc{⟨argument⟩}
。
如有⟨argument⟩
模式{⟨argument 1⟩}
,
\macrocatonearg{⟨argument 1⟩}
将会执行。
如有⟨argument⟩
模式{⟨argument 1⟩}{⟨argument 2⟩}
,
\macrocattwoargs{⟨argument 1⟩}{⟨argument 2⟩}
将会执行。
如有⟨argument⟩
模式{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}
,
\macrocatthreeargs{⟨argument 1⟩}{⟨argument 2⟩}{⟨argument 3⟩}
将会执行。
在所有其他情况下,错误消息都会通知用户有关语法错误。
因此你可以这样做,例如:
\macroc{{a}}
\macroc{{a}{b}}
\macroc{{a}{b}{c}}
\documentclass{article}
\makeatletter
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo,
%% \UD@gobble, \UD@gobbletwo, \UD@gobblethree
%% \UD@CheckWhetherNull, \UD@CheckWhetherBrace,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@gobble[1]{}%
\newcommand\UD@gobbletwo[2]{}%
\newcommand\UD@gobblethree[3]{}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument's first token is a catcode-1-character
%%.............................................................................
%% \UD@CheckWhetherBrace{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has leading
%% catcode-1-token>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked has no leading
%% catcode-1-token>}%
\newcommand\UD@CheckWhetherBrace[1]{%
\romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
\string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%=============================================================================
%% \macroc for processing one argument within which
%% you may have one or two or three brace-nested arguments:
%%-----------------------------------------------------------------------------
\newcommand\macrocatonearg[1]{C_#1}%
\newcommand\macrocattwoargs[2]{C_{#1}^{[#2]}}%
\newcommand\macrocatthreeargs[3]{C_{#1,#3}^{[#2]}}%
\newcommand\macrocatsyntaxerror{%
\@latex@error{Incorrect Syntax}{Specify either one or two or three arguments that are nested in braces.}%
}%
\newcommand\macroc[1]{%
\UD@CheckWhetherBrace{#1}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobble#1}{%
\macrocatonearg#1%
}{%
\expandafter\UD@CheckWhetherBrace\expandafter{\UD@gobble#1}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbletwo#1}{%
\macrocattwoargs#1%
}{%
\expandafter\UD@CheckWhetherBrace\expandafter{\UD@gobbletwo#1}{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobblethree#1}{%
\macrocatthreeargs#1%
}{\macrocatsyntaxerror}%
}{\macrocatsyntaxerror}%
}%
}{\macrocatsyntaxerror}%
}%
}{\macrocatsyntaxerror}%
}%
\makeatother
\begin{document}
\verb|$\macroc{{a}}$|: $\macroc{{a}}$ \bigskip
\verb|$\macroc{{a}{b}}$|: $\macroc{{a}{b}}$ \bigskip
\verb|$\macroc{{a}{b}{c}}$|: $\macroc{{a}{b}{c}}$ \bigskip
% Syntax-errors:
%
% $\macroc{{a}{b}{c}{d}}$
%
% $\macroc{ {a}}$
%
% $\macroc{{a} {b}}$
%
% $\macroc{a}$
%
% $\macroc{}$
\end{document}