我想定义一个宏,该宏定义一系列其他宏,每个宏都接受可变数量的参数(但在任何给定文档中都是固定的)。我知道我可以使用类似下面的方法来实现这一点:
\documentclass{standalone}
\newcommand\MakeCommands[1]{%
\ifcase#1\relax%
\or\newcommand\MyCommand[1]{##1}%
\or\newcommand\MyCommand[2]{##1, ##2}%
\or\newcommand\MyCommand[3]{##1, ##2, ##3}%
\or\newcommand\MyCommand[3]{##1, ##2, ##3, ##4}%
\fi%
}
\begin{document}
\MakeCommands{3}
\MyCommand{one}{two}{three}
\end{document}
但我确信有更好的方法可以做到这一点...我觉得是时候学会使用钥匙了......
有谁有更好的解决方案吗?
答案1
我建议创建一些键,用户可以决定是否使用。这也允许他们自由地以他们希望的顺序指定其中的一部分。这是一个使用xkeyval
:
\documentclass{article}
\usepackage{xkeyval}
\makeatletter
% ========= KEY DEFINITIONS =========
\define@cmdkey{mycmd}{one}[one]{}
\define@cmdkey{mycmd}{two}[two]{}
\define@cmdkey{mycmd}{three}[three]{}
\define@cmdkey{mycmd}{four}[four]{}
% ========= KEY DEFAULTS =========
\setkeys{mycmd}{one,two,three,four}% Defaults
\newcommand{\MyCommand}[1]{%
\begingroup%
\setkeys{mycmd}{two=SECOND,#1}% Set defaults for this macro + new keys
\texttt{one}: \cmdKV@mycmd@one;
\texttt{two}: \cmdKV@mycmd@two;
\texttt{three}: \cmdKV@mycmd@three;
\texttt{four}: \cmdKV@mycmd@four
\endgroup%
}
\makeatother
\begin{document}
\MyCommand{one}
\MyCommand{two=second,one=first,three=third}
\MyCommand{four=Last}
\end{document}
作为参考,请参阅如何创建带有键值的命令?。
答案2
我的答案只是 Werner 使用另一个工具给出的答案:不是使用xkeyval
,而是使用 TeX 原语的五行代码。结果与 Werner 的结果完全相同。
\def\kv#1{\expandafter\ifx\csname kv:#1\endcsname \relax \expandafter\kvunknown
\else \csname kv:#1\expandafter\endcsname\fi }
\def\kvunknown{???}
\def\kvscan #1#2=#3,{\ifx#1,\else \kvdef{kv:#1#2}{#3}\expandafter\kvscan\fi}
\def\kvdef#1{\expandafter\def\csname#1\endcsname}
\def\mymacro#1{\kvscan one=one, two=SECOND, three=three, four=four,,=,% implicit values
\kvscan#1,,=,% actual values
{\tt one}: \kv{one}; {\tt two}: \kv{two}; {\tt three}: \kv{three}; {\tt four}: \kv{four}
}
\mymacro{}
\mymacro{two=second, one=first, three=third}
\mymacro{four=Last}
如果有人认为这是在重新发明轮子,我不同意。对我来说,写这五行代码比阅读 72 页xkeyval
文档要简单得多。
答案3
如同沃纳的方法但使用expl3
:
\RequirePackage{expl3}
\ExplSyntaxOn
\clist_map_inline:nn { one , two , three , four }
{
\keys_define:nn { mycmd } { #1 .tl_set:c = { l__mycmd_ #1 _tl } }
}
\cs_new_protected:Npn \MyCommand #1
{
\group_begin:
\keys_set:nn { mycmd } {#1}
Key~values~are:
\clist_map_inline:nn { one , two , three , four }
{ ~ ##1 ~ = ~ ` \tl_to_str:c { l__mycmd_ ##1 _tl } ' }
\group_end:
}
\ExplSyntaxOff
\documentclass{article}
\begin{document}
\MyCommand{one = a}
\end{document}
我之所以更喜欢expl3
关键模块 ( l3keys
),xkeyval
是因为 的行为l3keys
在括号保留、空格剥离以及参数中的,
和类别代码=
方面都非常明确和清晰。我还发现xkyeval
界面相当尴尬(有点讽刺):l3keys
与 共享pgfkeys
。
\input expl3-generic
(如果您使用而不是,上述内容可以与其他格式一起使用\RequirePackage{expl3}
。如果您肯定以 LaTeX 为目标,我会使用它xparse
作为用户界面。)
答案4
我不知道这在什么意义上有用,但这里有一个选项xparse
。
\documentclass{scrartcl}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand \mycommand { g g g g g g g g g }
{
\seq_clear:N \l_tmpa_seq
\IfValueT { #1 } { \seq_put_right:Nn \l_tmpa_seq { #1 } }
\IfValueT { #2 } { \seq_put_right:Nn \l_tmpa_seq { #2 } }
\IfValueT { #3 } { \seq_put_right:Nn \l_tmpa_seq { #3 } }
\IfValueT { #4 } { \seq_put_right:Nn \l_tmpa_seq { #4 } }
\IfValueT { #5 } { \seq_put_right:Nn \l_tmpa_seq { #5 } }
\IfValueT { #6 } { \seq_put_right:Nn \l_tmpa_seq { #6 } }
\IfValueT { #7 } { \seq_put_right:Nn \l_tmpa_seq { #7 } }
\IfValueT { #8 } { \seq_put_right:Nn \l_tmpa_seq { #8 } }
\IfValueT { #9 } { \seq_put_right:Nn \l_tmpa_seq { #9 } }
\seq_use:Nn \l_tmpa_seq { , ~ }
}
\ExplSyntaxOn
\begin{document}
\mycommand{one}{two}{three}
\mycommand{one}{two}{three}{four}{five}{six}{seven}
\mycommand{one}{two}
\end{document}
它最多需要九个参数,并用逗号分隔。