macros

在调用宏之前展开参数

我已经在这个问题上敲了好几天的脑袋了。我有一个宏,它接受一个宏的名字和它的参数。然后,它重新排列参数,然后用重新排列的参数调用所传递的宏,这样就结束了。

#1{\arga}{\argb}{\argc}

其中 arga ... \argc 是处理后的参数。然而。 #1 中存储的宏之前,我需要完全展开 \arga ... \argc 。在玩了 \expandafter\noexpandetextools 等几天之后,我终生无法解决这个问题。我不能使用 expl3 ,我真的不想使用 etextoolsetoolbox 可用。这是一个MWE:

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  #1{\arga}{\argb}{\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

这导致“\arga \argb \argc”,但我想要“arg1arg2arg3”。 \expandafter 将在 \x 中执行此操作,但不会连续三个参数。 etextools 有一些宏可以做到这一点,但我真的想避免它(它在某些方面与 etoolbox 冲突,我必须有 etoolbox )。即使我尝试过( \ExpandNextTwo 等) ,我也无法让 etextools 宏工作

更新:我意识到,在我的案例中,args可以包含健壮的宏,比如。

\documentclass{article}
\usepackage{etoolbox}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \edef\argb{\ifstrequal{#3}{arg2}{arg2}{}}%
  \def\argc{#4}%
  {\protected\z{\noexpand#1{\arga}{\argb}{\argc}}\z}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

在这种情况下(以egreg的回答为例),它并没有完全展开。正如Joseph和egreg在下面提到的,这是不可能的,你只需要在这种情况下使用非健壮的宏,比如说。我将让这个问题保持原样,因为它是有信息量的。

“经典”方法是使用 \expandafter

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1%
    \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
      {\expandafter\expandafter\expandafter\arga\expandafter\expandafter\expandafter}%
        \expandafter\expandafter\expandafter{\expandafter\argb\expandafter}\expandafter
          {\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

我们需要这么多来扩展 arg3 然后 arg2 最后 arg1 。(这有效地包含在 expl3\exp_args:Nooo 中)。

\expandafter 数量的规则是 2 n – 1,其中n是我们想要扩展的令牌数。因此,对于前面某个地方的一个令牌,我们只需要在每个地方都有一个 \expandafter 被“跳过”,为了扩展两个令牌(第二个然后第一个),我们需要三个 \expandafter s,用于三个令牌(如当前情况) 我们需要七个 \expandafter ,所以需要一个。如果您在短时间内编写/打印出命令并划掉 TeX 会读取的命令,这是最容易看到的:您会发现一切正常。

随着 e-TeX 可用,我们可以使用 \edef\unexpanded

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \begingroup
    \edef\x{%
      \endgroup
      \noexpand#1
        {\unexpanded\expandafter{\arga}}%
        {\unexpanded\expandafter{\argb}}%
        {\unexpanded\expandafter{\argc}}%
    }%
  \x
}    

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

(你可以在没有 e-TeX 的情况下使用一系列 tok 来做同样的事情,但这有点令人困惑,所以我通常不会这样做。)


这个问题说没有 expl3 ,但相比之下,使用它提供的最小功能的方法将读取

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\def\x#1#2#3#4{
  \def\arga{#2}
  \def\argb{#3}
  \def\argc{#4}
  \exp_args:Nooo#1\arga\argb\argc
}    
\ExplSyntaxOff
\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

我希望这更具可读性。(我可能想使用 \exp_args:NVVV ,因为我们正在使用“存储在变量中的值”,但该函数不是预定义的,所以我在这里避免了它。)




如果您真的希望完全扩展参数,那么

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \begingroup\edef\z{\endgroup\noexpand#1{#2}{#3}{#4}}\z
}

\def\y#1#2#3{\detokenize{#1#2#3}}

\def\foo{This is foo}

\texttt{\x\y{arg1}{arg2}{arg3\foo}}

\end{document}

将导致打印

arg1arg2arg3This is foo

而基于 \expandafter 的解决方案将打印

arg1arg2arg\foo