根据其他宏名称定义宏

根据其他宏名称定义宏

请参阅下面的定义机制,其中我根据另外两个宏定义来定义一个宏。

\documentclass{article}

\begin{document}

\def\a{A}
\def\b{B}
\def\c{CC}


\def\expandafter\csname\a\b\endcsname{\c}

\AB

\end{document}

我定义它的方式是,我认为\a\b正在构建 AB。因此,\AB应该扩展到CC

但执行时,我收到消息,

! Undefined control sequence.
l.12 \AB

?

该文件无需\AB调用即可顺利编译。因此,某种定义机制正在发生。

我的错误在哪里?

答案1

使用您当前的代码

\def\expandafter\csname\a\b\endcsname{\c}

你正在覆盖TeX 原语\expandafter,这样它必须随后是\csname\a\b\endcsname。然后构造

\expandafter\csname\a\b\endcsname

将扩展为\c。对于空文档,什么也不会发生,但是尝试输入一些内容,你就会得到一个令人费解的

! Use of \expandafter doesn't match its definition.

想要的是坚持\def一段时间,所以你必须把\expandafter它。代码

\documentclass{article}

\begin{document}

\def\a{A}
\def\b{B}
\def\c{CC}
\expandafter\def\csname\a\b\endcsname{\c}
\AB
\end{document}

将会按照您的期望进行。

我最喜欢阅读的是\expandafter教程\expandafter(拖船 9)

答案2

控制序列\a\b\c已经在 LaTeX 2ε 内核中定义。

\MYa\MYb并将\MYc改用。

为了更好地体验 (La)TeX 的扩展机制,我提供了以下方法:

使用这种方法\csname可以触发扩展直到找到匹配项,并与诱骗 LaTeX 扩展 -construct 后面的内容\endcsname结合使用:\expandafter\csname..\endcsname

% Use LaTeX for compiling this:

\newcommand*\MYa{A}
\newcommand*\MYb{B}
\newcommand*\MYc{CC}

\expandafter\newcommand\csname\MYa\MYb\expandafter\endcsname\expandafter{\MYc}

\show\AB

\stop

您还可以\expandafter结合\exchange

% Use LaTeX for compiling this:

\newcommand\exchange[2]{#2#1}

\newcommand*\MYa{A}
\newcommand*\MYb{B}
\newcommand*\MYc{CC}

\expandafter\exchange\expandafter{\expandafter{\MYc}}{\expandafter\newcommand\csname\MYa\MYb\endcsname}%

\show\AB

\stop

在许多情况下,添加花括号的变体\exchange很有用:

% Use LaTeX for compiling this:

\newcommand\PassFirstToSecond[2]{#2{#1}}

\newcommand*\MYa{A}
\newcommand*\MYb{B}
\newcommand*\MYc{CC}

\expandafter\PassFirstToSecond\expandafter{\MYc}{\expandafter\newcommand\csname\MYa\MYb\endcsname}%

\show\AB

\stop

还有一个宏\name,它将一个参数的第一对花括号之前的所有内容以及另一个参数的第一对花括号内的所有内容应用\csname..\endcsname到花括号内的内容后返回内容:

\name\newcommand{macro}...\newcommand\macro...
\name\global\long\def{macro}...\global\long\def\macro...
\name\string{macro}\string\macro
\name{macro}\macro
\name\name\let{macroA}={macroB}\name\let\macroA={macroB}\let\macroA=\macroB

 

% Use LaTeX for compiling this:

\newcommand*\MYa{A}
\newcommand*\MYb{B}
\newcommand*\MYc{CC}

\newcommand\exchange[2]{#2#1}%    
\csname @ifdefinable\endcsname\name{%
  \long\def\name#1#{\romannumeral0\innername{#1}}%
}%
\newcommand\innername[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}%
}%

\name\expandafter\newcommand\expandafter{\MYa\MYb}\expandafter{\MYc}%
% ->
% \romannumeral0\innername{\expandafter\newcommand\expandafter}{\MYa\MYb}\expandafter{\MYc}
% ->
% %\romannumeral0-expansion in progress
% \expandafter\exchange\expandafter{\csname\MYa\MYb\endcsname}{ \expandafter\newcommand\expandafter}\expandafter{\MYc}%
% -> ( \expandafter-chain "hits" \csname )
% %\romannumeral0-expansion in progress
% \exchange{\AB}{ \expandafter\newcommand\expandafter}\expandafter{\MYc}%
% ->
% %\romannumeral0-expansion in progress
% <space>\expandafter\newcommand\expandafter\AB\expandafter{\MYc}%
% ->
% %\romannumeral0-expansion terminated:
% \expandafter\newcommand\expandafter\AB\expandafter{\MYc}%
% -> ( \expandafter-chain "hits" \MYc )
% \newcommand\AB{CC}%

\show\AB

\stop

如果\PassFirstToSecond有的话:

% Use LaTeX for compiling this:

\newcommand*\MYa{A}
\newcommand*\MYb{B}
\newcommand*\MYc{CC}

\newcommand\PassFirstToSecond[2]{#2{#1}}%    
\newcommand\exchange[2]{#2#1}%    
\csname @ifdefinable\endcsname\name{%
  \long\def\name#1#{\romannumeral0\innername{#1}}%
}%
\newcommand\innername[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}%
}%

\expandafter\PassFirstToSecond\expandafter{\MYc}{\name\newcommand*{\MYa\MYb}}%

\show\AB

\stop

我最喜欢阅读\expandafter(以及如何保持简短\expandafter)的是线程“如何知道附加到 csname 宏时的 expandafter 数量”。 ;-)

相关内容