引入许多新命令

引入许多新命令

我有一个文档大量使用预定义符号(以便以后更改它们),即:

\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...\endcsnamecs表示“控制序列”)。虽然\<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}                 

相关内容