我已经使用 latex 有一段时间了,但仅限于最基本的功能。我尽可能使用软件包。我现在正在尝试自己编写一些代码,以使我的 latex 文档更简洁。这就是我想要实现的目标:
当我定义:
\symb{flow}{f_#1^#2}[a,b]
我希望能够使用
\flow % outputs $f_a^b$
\flow[x,y] % outputs $f_x^y$
请注意,索引的数量不一定是 2,可以是 1,也可以大于 2。
以下是我现在所拥有的:
\NewDocumentCommand{\symb}{m m m}
{ \expandafter\NewDocumentCommand\csname#1\endcsname{>{\SplitList{,}}O{#3}}
{
% Not sure what I need to write here
}
}
基本上,我希望能够使用它\symb{flow}{f_#1^#2}[a,b]
来定义一个接受可选参数的宏\flow
,该参数是变量的逗号分隔索引。如果没有提供可选参数,则将使用默认索引(在本例中为 a、b)。
在 Python 中,可以写成:
def symb(expr, default):
def fn(*args):
if len(args) == 0:
return expr % args
else:
return expr % default
return fn
flow = symb('$f_%s^%s$', (a, b))
flow() % outputs $f_a^b$
flow(x, y) % outputs $f_x^y$
答案1
你可以这样做,但你不应该将 Python 作为 LaTeX 编程的模型。
在 LaTeX 中,参数是用括号括起来的,不能用逗号列表代替。
无论如何,这里有一个在模板中有任意数量参数的实现(但你当然必须指定你想要多少个)。
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\symb}{mmmm}
{% #1=name of command to define, #2=number of args, #3=template, #4=default
% define the internal version
\cs_new_protected:cn { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } { #3 }
% define the external version
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
{
\__kelvin_symb_do:nnx { #1 } { #2 } { \clist_map_function:nN { ##1 } \__kelvin_symb_brace:n }
}
}
\cs_new:Nn \__kelvin_symb_do:nnn
{
\use:c { kelvin_symb_#1:\prg_replicate:nn{#2}{n} } #3
}
\cs_generate_variant:Nn \__kelvin_symb_do:nnn { nnx }
\cs_new:Nn \__kelvin_symb_brace:n { {#1} }
\ExplSyntaxOff
\symb{flow}{2}{f_{#1}^{#2}}{a,b}
\symb{foo}{4}{\int_{#1}^{#2}#3\,d#4}{0,1,x,x}
\begin{document}
$\flow$
$\flow[x,y]$
$\foo$
$\foo[a,b,f(x),x]$
\end{document}
关于代码还有更多话要说。首先是简单的事情:
\exp_args:Nc \NewDocumentCommand { #1 } { O{#4} }
是expl3
版本
\expandafter\NewDocumentCommand\csname#1\endcsname { O{#4 } }
并且应被优先考虑。
接下来介绍其\symb
工作原理。首先,它定义一个内部函数,其参数数量与声明的一样多;其替换文本由给定的模板提供。因此\symb{flow}{2}{f_{#1}^{#2}}{a,b}
定义
\kelvin_symb_flow:nn { f_{#1}^{#2} }
_
注意。是 范围内的字母这一事实没有问题,因为给出了\ExplSyntaxOn
声明\symb{flow}{2}{...}{...}
外部那个范围。
之后我们定义一个用户级命令\flow
,该命令带有一个可选参数,其默认值是 的第四个参数\symb
。该命令通过 间接调用了前面定义的函数\__kelvin_symb_do:nnx
。
在本例中,第一个参数是 ,flow
第二个参数是参数的数量;它们的目的是能够调用内部函数。最后一个参数是逗号列表(默认值或作为 的可选参数给出的列表\flow
),但经过预处理,以便生成一个括号项列表。
正常版本\__kelvin_symb_do:nnn
只是形成内部函数\kelvin_symb_flow:nn
并取消第三个参数的括号。但我们使用的是其变体;当
\clist_map_function:nN { #1 } \__kelvin_symb_brace:n
完全展开(因为x
变体),如果应用到a,b
它会产生{a}{b}
。因此我们最终得到
\kelvin_symb_flow:nn { a } { b }
并且 LaTeX 很高兴像往常一样扩展到f_{a}^{b}
。
答案2
例如,你可以使用这个:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\symb#1#2[#3,#4]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:b\endcsname[#3,#4]\fi}%
\sdef{#1:b}[##1,##2]{#2}%
}
\symb{flow}{f_#1^#2}[a,b]
$\flow$ and $\flow[x,y]$.
该宏的第二个版本根据评论实现了您的要求:
\def\sdef#1{\expandafter\def\csname#1\endcsname}
\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\symb#1#2[#3]{%
\sdef{#1}{\expandafter\futurelet\expandafter\next\csname#1:a\endcsname}%
\sdef{#1:a}{\ifx\next[\csname#1:b\expandafter\endcsname
\else \csname#1:c\endcsname #3,,,,,,,,\end \fi}%
\sdef{#1:b}[##1]{\def\paramslistA{#3,}\def\paramslistB{}\setparams ##1,\end,
\csname#1:c\expandafter\endcsname \paramslistB,,,,,,,,\end}%
\sdef{#1:c}##1,##2,##3,##4,##5,##6,##7,##8,##9\end{#2}%
}
\def\setparams #1,{\ifx\end#1%
\expandafter\addto\expandafter\paramslistB\expandafter{\paramslistA}%
\else \expandafter \setparamslist \paramslistA \end #1,%
\expandafter\setparams\fi}
\def\setparamslist#1,#2\end#3,{\def\paramslistA{#2}\addto\paramslistB{#3,}}
\symb{flow}{f_#1^#2}[a,b]
\symb{test}{test: 1=#1, 2=#2, 3=#3, 4=#4}[a,b,c,d]
$\flow$ and $\flow[x,y]$.
\test
\test[mmm]
\test[x,y,z]
这个解决方案与 egreg 的解决方案不同:您不需要解释复杂的宏,只需要使用 TeX 原语。
答案3
这与 wipet 类似,但强制要求 symb 参数,如评论中所述
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1\relax}}
\def\splitcomma#1#2,#3\relax{#1{#2}{#3}}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
$\flow$
$\flow[x,y]$
\end{document}
还有一个版本允许参数列表中有多个(最多 8 个)条目。
\documentclass{article}
\def\symb#1#2#3{%
\expandafter\def\csname x#1\endcsname##1##2##3##4##5##6##7##8##9{#2}%
\expandafter\newcommand\csname #1\endcsname[1][#3]{%
\expandafter\splitcomma\csname x#1\endcsname ##1,,,,,,,,,,\relax}}
\def\splitcomma#1#2,#3,#4,#5,#6,#7,#8,#9\relax{#1{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}\relax}
\begin{document}
\symb{flow}{f_#1^#2}{a,b}
\symb{flowb}{f_#1^#2g_#3^#4}{a,b,c,d}
$\flow$
$\flow[x,y]$
$\flowb$
$\flowb[x,y,w,z]$
\end{document}