我有一个文档大量使用预定义符号(以便以后更改它们),即:
\newcommand{\term}{t}
...
现在我需要介绍符号的不同注释变体:
\newcommand{\aterm}{\term^{\alpha}}
\newcommand{\bterm}{\term^{\beta}}
...
手动管理这些集合非常繁琐(特别是在添加新符号或删除过时符号时)。
所以我自然想知道,如何在一个批处理中定义多个(不同前缀的)参数?由于 TeX 的宏功能,这当然是可能的,但有没有一种安全方便的方法呢?
即是否存在一些“元”新命令,其工作方式有点像这样:
\metanewcommand{\declaresymbols}[2]{\newcommand{\#1term}{t^{#2}} ... }
编辑:感谢下面史蒂文的评论,我能够实现我自己需要的东西:
\newcommand{\declaresymbol}[4]{
%introduce a symbol \#3 -> #4 prefixed with #1 and annotated with #2
\ifthenelse{\equal{#1}{}}{
\expandafter\newcommand\csname#3\endcsname{#4}
} {
\expandafter\newcommand\csname#1#3\endcsname{#4^{#2}}
}
}
\newcommand{\declaresymbols}[2]{
\declaresymbol{#1}{#2}{val}{v}
\declaresymbol{#1}{#2}{term}{t}
}
% Standard symbol, no variant
\declaresymbols{}{} %gives \term -> t and \val -> v
% Alpha variant
\declaresymbols{a}{\alpha} %gives \aterm -> t^\alpha \aval -> v^\alpha
答案1
您正在寻找的是 plain-TeX 指令\csname...\endcsname
(cs
表示“控制序列”)。虽然\<macro-name>
语法要求宏名称是预定义的 11 个字母的 catcode 序列,但分隔\csname...\endcsname
符之间的内容可以包括其他 catcode 的符号,并且可以包括在调用时评估的变量。
除此之外,唯一的技巧是\expandafter
在定义之前使用\newcommand
,以便\csname
扩展为实际的控制序列。
\documentclass{article}
\newcommand{\declaresymbols}[2]{\expandafter\newcommand\csname#1term\endcsname{t^{#2}}}
\begin{document}
\declaresymbols{a}{\alpha}
\declaresymbols{b}{\beta}
$\aterm \ne \bterm$
\end{document}
cs
如果您在编程领域做了很多工作,像这样的软件包etoolbox
非常有用,它提供了整个宏系列,可以让您以更自然的方式使用这种棘手的语法。
答案2
你可以做
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand\definesymbol{omm}
{
\IfNoValueTF{#1}
{ \cs_new:cpn {#2} { #3 } }
{ \cs_new:cpn { #2 #1 } { \use:c { #1 } \sp { #3 } } }
}
\ExplSyntaxOff
\definesymbol{term}{t}
\definesymbol[term]{a}{\alpha}
\definesymbol[term]{b}{\beta}
\definesymbol{X}{X}
\definesymbol[X]{a}{a}
\begin{document}
$\term+\aterm+\bterm+\X+\aX$
\end{document}
没有可选参数的调用定义了主宏,使用可选参数则添加了上标和前缀。
由于 Ulrich Diez 发起了一项竞赛,这里有一个与他的解决方案类似的解决方案,但代码更少,语法更友好。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected:Nn \choeger_declare_single_symbol:nnnnnn
{
% {<macro-name of base-symbol>}
% {<coding of base symbol>}
% {<symbol-macro-name-prefix>}
% {<symbol-macro-name-postfix>}
% {<coding of preceding operands and operators>}
% {<coding of trailing operands and operators>}
\cs_new_protected:cpn { #3#1#4 } { #5{#2}#6 }
}
\cs_new_protected:Nn \choeger_declare_symbol_family:nnn
{
% {<macro-name of base-symbol>}
% {<coding of base symbol>}
% {<list of sequences {prefix}{postfix}{prefix code}{postfix code}>}
% define the base symbol
\cs_new_protected:cpn { #1 } { {#2} }
% define the others
\clist_map_inline:nn { #3 }
{
\choeger_declare_single_symbol:nnnnnn { #1 } { #2 } ##1
}
}
\cs_new_protected:Nn \choeger_declare_symbol_families:nn
{
% {<list of sequences {name}{code}>}
% {<list of sequences {prefix}{postfix}{prefix code}{postfix code}>}
\clist_map_inline:nn { #1 }
{
\choeger_declare_symbol_family:nnn ##1 { #2 }
}
}
\NewDocumentCommand{\DeclareSymbolFamilies}{mm}
{
\choeger_declare_symbol_families:nn { #1 } { #2 }
}
\ExplSyntaxOff
\DeclareSymbolFamilies
{
{Foo}{\langle\mathit{Foo}\rangle},
{Term}{t},
{Val}{v},
}
{
{}{RaisedToPowerAlpha}{}{^\alpha},
{MultiplyBetaWith}{}{\beta\cdot}{},
{}{MultipiedWithGamma}{}{\cdot\gamma},
{RaiseDeltaToThePowerOf}{}{\delta^}{},
{MultiplyBetaWith}{AndAddTwo}{\beta\cdot}{+2},
{MultiplyBetaWith}{AfterAddingTwo}{\beta\cdot(}{+2)},
{DivideBetaBy}{}{\left(\frac{\beta}}{\right)},
{Divide}{ByBeta}{\left(\frac}{{\beta}\right)},
}
\begin{document}
\setlength{\parindent}{0pt}
\verb|\Foo|: $\Foo$\\
\verb|\FooRaisedToPowerAlpha|: $\FooRaisedToPowerAlpha$\\
\verb|\MultiplyBetaWithFoo|: $\MultiplyBetaWithFoo$\\
\verb|\FooMultipiedWithGamma|: $\FooMultipiedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfFoo|: $\RaiseDeltaToThePowerOfFoo$\\
\verb|\MultiplyBetaWithFooAndAddTwo|: $\MultiplyBetaWithFooAndAddTwo$\\
\verb|\MultiplyBetaWithFooAfterAddingTwo|: $\MultiplyBetaWithFooAfterAddingTwo$\\
\verb|\DivideBetaByFoo|: $\DivideBetaByFoo$\\
\verb|\DivideFooByBeta|: $\DivideFooByBeta$
\bigskip
\verb|\Term|: $\Term$\\
\verb|\TermRaisedToPowerAlpha|: $\TermRaisedToPowerAlpha$\\
\verb|\MultiplyBetaWithTerm|: $\MultiplyBetaWithTerm$\\
\verb|\TermMultipiedWithGamma|: $\TermMultipiedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfTerm|: $\RaiseDeltaToThePowerOfTerm$\\
\verb|\MultiplyBetaWithTermAndAddTwo|: $\MultiplyBetaWithTermAndAddTwo$\\
\verb|\MultiplyBetaWithTermAfterAddingTwo|: $\MultiplyBetaWithTermAfterAddingTwo$\\
\verb|\DivideBetaByTerm|: $\DivideBetaByTerm$\\
\verb|\DivideTermByBeta|: $\DivideTermByBeta$
\bigskip
\verb|\Val|: $\Val$\\
\verb|\ValRaisedToPowerAlpha|: $\ValRaisedToPowerAlpha$\\
\verb|\MultiplyBetaWithVal|: $\MultiplyBetaWithVal$\\
\verb|\ValMultipiedWithGamma|: $\ValMultipiedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfVal|: $\RaiseDeltaToThePowerOfVal$\\
\verb|\MultiplyBetaWithValAndAddTwo|: $\MultiplyBetaWithValAndAddTwo$\\
\verb|\MultiplyBetaWithValAfterAddingTwo|: $\MultiplyBetaWithValAfterAddingTwo$\\
\verb|\DivideBetaByVal|: $\DivideBetaByVal$\\
\verb|\DivideValByBeta|: $\DivideValByBeta$
\end{document}
答案3
一些嵌套循环可能会起到这样的作用:
\documentclass{article}
\usepackage{amsmath, textcomp}
\makeatletter
%%-----------------------------------------------------------------------------
%% 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>
%%
%% A concern in his posting is that the argument is hit with \string
%% after some expansions which in edge cases might result in unbalancing
%% surrounding \if..\fi-constructs if the macro is used inside of such
%% \if..\fi-constructs.
%%
%% That challenging concern sickened me. ;-)
%%
%% Therefore I decided to implerment a variant where this cannot happen
%% as expansion is forced by \romannumeral:
%%
%% After the first expansion-step, \string is not applied yet.
%% After the second expansion-step, any possibly disturbing remainders
%% are already removed due to \romannumeral-expansion.
%%
%% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral,
%% digit 0, space token for terminating \romannumeral-expansion,
%% \string, \expandafter, \@firstoftwo, \@secondoftwo, {, }.
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Fully expandable for-loop:
%%.............................................................................
%% \UD@DoWithEachElementOfArgumentList{<action>}%
%% {<action when no (more) arguments are in list>}%
%% {<preset>}%
%% {{<e_k>}{<e_(k+1)>}..{<e_n>}}
%%
%% yields (after two expansion-steps) :
%%
%% <action>{<e_k>}<preset>%
%% <action>{<e_(k+1)>}<preset>%
%% ...
%% <action>{<e_n>}<preset>%
%% <action when no (more) arguments are in list>%
%%
\newcommand\UD@Exchange[2]{#2#1}%
\newcommand\UD@KeepOnlyFirstBeforeSeLDoM{}%
\long\def\UD@KeepOnlyFirstBeforeSeLDoM#1#2\SeLDoM{{#1}}%
\newcommand\UD@DoWithEachElementOfArgumentList{%
\romannumeral0\UD@MoveElementFromList{}{ }%
}%
\newcommand\UD@MoveElementFromList[6]{%
\UD@CheckWhetherNull{#1}{%
\expandafter\UD@CheckWhetherNull\expandafter{\@secondoftwo#6.{}}{#2#4}{%
\expandafter\expandafter\expandafter\UD@MoveElementFromList
\expandafter\UD@Exchange
\expandafter{%
\expandafter{\@firstoftwo{}#6}}{{#6\SeLDoM}{#2}{#3}{#4}{#5}}%
}%
}{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\UD@MoveElementFromList{}{#2#3#1#5}}%
{\expandafter\UD@MoveElementFromList
\expandafter{\UD@KeepOnlyFirstBeforeSeLDoM#1}{#2}%
}{#3}{#4}{#5}{#6}%
}%
}%
%%-----------------------------------------------------------------------------
%% \DeclareASingleSymbol{<symbol-macro-name-prefix>}%
%% {<symbol-macro-name-postfix>}%
%% {<coding of base symbol / coding of preceding operands and operators>}%
%% {<coding of trailing operands and operators>}%
%% {<macro-name of base-symbol>}
%%.............................................................................
\newcommand\DeclareASingleSymbol[5]{%
\UD@CheckWhetherNull{#1#2}{%
\expandafter\newcommand\csname#5\endcsname{#3}%
}{%
\expandafter\newcommand\csname#1#5#2%
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter\endcsname
\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{%
\csname#5\endcsname#4}{#3}}%
}%
}%
%%-----------------------------------------------------------------------------
%% \DeclareOneSymbolFamily
%% {<macro-name of base-symbol>}%
%% {<coding of base-symbol>}%
%% {%
%% {{<symbol-macro-name-prefix 1>}{<symbol-macro-name-postfix 1>}{<coding of preceding operands and operators 1>}{<coding of trailing operands and operators 1>}}%
%% {{<symbol-macro-name-prefix 2>}{<symbol-macro-name-postfix 2>}{<coding of preceding operands and operators 2>}{<coding of trailing operands and operators 2>}}%
%% ..
%% {{<symbol-macro-name-prefix n>}{<symbol-macro-name-postfix n>}{<coding of preceding operands and operators n>}{<coding of trailing operands and operators n>}}%
%% }%
%%
%%.............................................................................
\newcommand\DeclareOneSymbolFamily[3]{%
\UD@DoWithEachElementOfArgumentList{\expandafter\DeclareASingleSymbol\@firstofone}%
{}%
{{#1}}%
{{{}{}{#2}{}}#3}%
}%
%%-----------------------------------------------------------------------------
%% \DeclareSeveralSymbolFamilies{%
%% {{<macro-name of base-symbol 1>}{<coding of base-symbol 1>}%
%% {{<macro-name of base-symbol 2>}{<coding of base-symbol 2>}}%
%5 ..
%% {{<macro-name of base-symbol k>}{<coding of base-symbol k>}}%
%% }{%
%% {{<symbol-macro-name-prefix 1>}{<symbol-macro-name-postfix 1>}{<coding of preceding operands and operators 1>}{<coding of trailing operands and operators 1>}}%
%% {{<symbol-macro-name-prefix 2>}{<symbol-macro-name-postfix 2>}{<coding of preceding operands and operators 2>}{<coding of trailing operands and operators 2>}}%
%% ..
%% {{<symbol-macro-name-prefix n>}{<symbol-macro-name-postfix n>}{<coding of preceding operands and operators n>}{<coding of trailing operands and operators n>}}%
%% }
%%
%%.............................................................................
\newcommand\DeclareSeveralSymbolFamilies[2]{%
\UD@DoWithEachElementOfArgumentList{\expandafter\DeclareOneSymbolFamily\@firstofone}%
{}%
{{#2}}%
{#1}%
}%
\makeatother
\DeclareSeveralSymbolFamilies{%
{{Foo}{{\mathit{\text{\textlangle}Foo\text{\textrangle}}}}}%
{{Term}{t}}%
{{Val}{v}}%
}{%
{{}{RaisedToPowerAlpha}{}{^\alpha}}%
{{MulitplyBetaWith}{}{\beta\cdot}{}}%
{{}{MulipliedWithGamma}{}{\cdot\gamma}}%
{{RaiseDeltaToThePowerOf}{}{\delta^}{}}%
{{MulitplyBetaWith}{AndAddTwo}{\beta\cdot}{+2}}%
{{MulitplyBetaWith}{AfterAddingTwo}{\beta\cdot(}{+2)}}%
{{DivideBetaBy}{}{\left(\frac{\beta}}{\right)}}%
{{Divide}{ByBeta}{\left(\frac}{{\beta}\right)}}%
}%
\begin{document}
\verb|\Foo|: $\Foo$\\
\verb|\FooRaisedToPowerAlpha|: $\FooRaisedToPowerAlpha$\\
\verb|\MulitplyBetaWithFoo|: $\MulitplyBetaWithFoo$\\
\verb|\FooMulipliedWithGamma|: $\FooMulipliedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfFoo|: $\RaiseDeltaToThePowerOfFoo$\\
\verb|\MulitplyBetaWithFooAndAddTwo|: $\MulitplyBetaWithFooAndAddTwo$\\
\verb|\MulitplyBetaWithFooAfterAddingTwo|: $\MulitplyBetaWithFooAfterAddingTwo$\\
\verb|\DivideBetaByFoo|: $\DivideBetaByFoo$\\
\verb|\DivideFooByBeta|: $\DivideFooByBeta$\\
\verb|\Term|: $\Term$\\
\verb|\TermRaisedToPowerAlpha|: $\TermRaisedToPowerAlpha$\\
\verb|\MulitplyBetaWithTerm|: $\MulitplyBetaWithTerm$\\
\verb|\TermMulipliedWithGamma|: $\TermMulipliedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfTerm|: $\RaiseDeltaToThePowerOfTerm$\\
\verb|\MulitplyBetaWithTermAndAddTwo|: $\MulitplyBetaWithTermAndAddTwo$\\
\verb|\MulitplyBetaWithTermAfterAddingTwo|: $\MulitplyBetaWithTermAfterAddingTwo$\\
\verb|\DivideBetaByTerm|: $\DivideBetaByTerm$\\
\verb|\DivideTermByBeta|: $\DivideTermByBeta$\\
\verb|\Val|: $\Val$\\
\verb|\ValRaisedToPowerAlpha|: $\ValRaisedToPowerAlpha$\\
\verb|\MulitplyBetaWithVal|: $\MulitplyBetaWithVal$\\
\verb|\ValMulipliedWithGamma|: $\ValMulipliedWithGamma$\\
\verb|\RaiseDeltaToThePowerOfVal|: $\RaiseDeltaToThePowerOfVal$\\
\verb|\MulitplyBetaWithValAndAddTwo|: $\MulitplyBetaWithValAndAddTwo$\\
\verb|\MulitplyBetaWithValAfterAddingTwo|: $\MulitplyBetaWithValAfterAddingTwo$\\
\verb|\DivideBetaByVal|: $\DivideBetaByVal$\\
\verb|\DivideValByBeta|: $\DivideValByBeta$\\
\end{document}