macros

マクロ呼び出し前の引数の展開

何日も前から頭を打ち付けています。私はマクロ名とその引数を取るマクロを持っています。そして、引数を少しアレンジして、アレンジされた引数で渡されたマクロを呼び出すので、このように終了します。

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

arga arga ... \argc は処理された引数です。でも。 #1 に格納されたマクロが呼び出される前に、 \arga ... \argc を完全に展開する必要があります。 \expandafter\noexpandetextools などで何日も遊んだ後、これを解決することはできません。 expl3 を使用できず、 etoolbox を使用したくないのですが、 etextools が利用可能です。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 でこれを行いますが、連続した 3 つの引数に対しては行いません。 etextools にはこれを行うためのマクロがいくつかありますが、私は本当にそれを避けたいと思っています (いくつかの点で etoolbox と衝突し、 etoolbox が必要です)。 etextools マクロを動作させることができませんでした( \ExpandNextTwo など)。

UPDATE:私の場合、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 Nooo に効果的にラップされているものです)。

\expandafter の数の規則は 2 n – 1 です。ここで、nは拡張したいトークンの数です。したがって、どこか先の 1 つのトークンの場合、「スキップ」する各場所に 1 つの \expandafter だけが必要です。2 つのトークンを展開するには (2 つ目のトークン、次に最初のトークン)、3 つのトークンに対して 3 つの \expandafter が必要です(現在の場合のように) ) 7 つの \expandafter が必要です。これは、TeX がコマンドを読み取るのと同じように、コマンドを少し書き込んで印刷し、取り消し線を引くと、最も簡単に確認できます。すべてがうまくいくことがわかります。

e-TeX が利用できるので、 \edef\unexpanded 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}

(一連の toks を使用して e-TeX なしで同じことを行うことができますが、少し混乱するので、通常は行いません。)


質問には no 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