\documentclass{article}
\makeatletter
\usepackage{ltxcmds}
\newcounter{mycounter}
\setcounter{mycounter}{7}
\newcommand{\mysndc}[3]{#1 #2 #3}
\newcommand{\mycommand}{}
\newcommand{\mytrdc}[1]{\ltx@GlobalAppendToMacro{\mycommand}{%
\mysndc{\arabic{mycounter}}{#1}{\thepage}}}
\makeatother
\begin{document}
x
\mytrdc{8}
\newpage
\setcounter{mycounter}{4}
\mycommand
\end{document}
当\mycommand
调用时,\mysndc{\arabic{mycounter}}{8}{\thepage}
结果是4 8 2
。我希望结果是\mysndc{7}{8}{2}
。7 8 1
为了实现这一点,必须在将参数添加到\mysndc
之前扩展。应该是有用的,但它的不同位置(也不止一个)并没有产生预期的结果,例如\mysndc
\mycommand
\expandafter
\expandafter
\newcommand{\mytrdc}[1]{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\ltx@GlobalAppendToMacro{\mycommand\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\mysndc\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter{\expandafter\expandafter\expandafter\arabic{mycounter}\expandafter\expandafter\expandafter}\expandafter\expandafter\expandafter{\expandafter#1\expandafter}\expandafter{\thepage}}}
。在将其附加到之前,我必须在哪里放置多少个\expandafter
s 来扩展它的参数,以及具体原因是什么?我在 tex.SE 上找到了许多类似的问题和答案,但仍然无法正确回答。如果可能的话,我更喜欢使用s 的解决方案,这样我就可以从中学习,而无需使用 e-TeX/etextools/etextoolbox/LaTeX3/...\mysndc
\mycommand
expandafter
答案1
解决这个问题的最简单方法可能是使用强制扩展所有内容\edef
,因为这样我们就避免了需要改组参数。 (\mytrdc
在任何情况下都是不可扩展的,因此我们可以使用赋值。)一种可能的方法是使用\edef
:
\documentclass{article}
\usepackage{ltxcmds}
\newcounter{mycounter}
\setcounter{mycounter}{7}
\newcommand{\mysndc}[3]{#1 #2 #3}
\newcommand{\mycommand}{}
\makeatletter
\newcommand{\mytrdc}[1]{%
\begingroup
\edef\x{%
\endgroup
\noexpand\ltx@GlobalAppendToMacro{\noexpand\mycommand}{%
\noexpand\mysndc{\arabic{mycounter}}{#1}{\thepage}}}%
\x}
\makeatother
\begin{document}
x
\mytrdc{8}
\newpage
\setcounter{mycounter}{4}
\show\mycommand
\end{document}
这个想法很简单:创建一个临时的\edef
ed 宏\x
,其中包含所需的扩展材料以及必要的“设置”,然后执行它。一切都是在一个组中完成的,这样我们就不会弄乱 的任何其他含义\x
。
答案2
你可以用 来做\expandafter
,但是它会很长,因为从 到\arabic{mycounter}
7 需要四步扩展:
\arabic{mycounter}
\expandafter \@arabic \csname c@mycounter\endcsname
\@arabic \c@mycounter
\number \c@mycounter
7
扩展\thepage
需要多一步,因为第一级扩展是\arabic{page}
。
让我们看一个更简单的例子。你有
\newcommand{\mymacro}[1]{\dosomething{#1}}
你的“附加”宏在哪里\dosomething
,你想要的#1
是参数扩展后的“最终”结果。所以,如果你有
\def\foo{A}
你想要的\dosomething
是A
,而不是\foo
。这很容易:
\expandafter\mymacro\expandafter{\foo}
如果你有
\def\foo{\baz}\def\baz{A}
您需要扩展\foo
两次:
\expandafter\expandafter\expandafter\mymacro
\expandafter\expandafter\expandafter{\foo}
一般来说,如果你想要 n 个扩展,你需要 2 n -1 个\expandafter
标记。在 的情况下,\arabic{mycounter}
你需要 之前和 之后各 15 个标记\mymacro
。因为\thepage
它们将是 31 个。但是由于有三个参数,事情变得复杂了!
因此需要一种不同的方法。最简单的方法是使用\edef
或,以防您的参数可能包含诸如 之类的“危险”内容\textbf
,则使用\protected@edef
;我将以与 Joseph 的答案略有不同的方式进行操作,只是为了好玩。
\documentclass{article}
\usepackage{etoolbox}
\newcounter{mycounter}
\setcounter{mycounter}{7}
\newcommand{\mysndc}[3]{#1 #2 #3}
\newcommand{\mycommand}{}
\makeatletter
\newcommand{\mytrdc}[1]{%
\begingroup
\protected@edef\x{{\arabic{mycounter}}{#1}{\thepage}}%
\expandafter\endgroup
\expandafter\gappto\expandafter\mycommand\expandafter
{\expandafter\mysndc\x}%
}
\makeatother
\begin{document}
x
\mytrdc{8}
\newpage
\setcounter{mycounter}{4}
\texttt{\meaning\mycommand}
\end{document}
临时宏\x
将扩展为{7}{8}{1}
,并且在执行 的链式操作后它将消失(扩展\expandafter
后该组将结束) 。\x
这是使用 LaTeX3 的另一种方法。
\documentclass{article}
\usepackage{xparse}
\newcounter{mycounter}
\newcommand{\mysndc}[3]{#1 #2 #3}
\ExplSyntaxOn
\NewDocumentCommand{\mytrdc}{ m }
{
\stephen_mytrdc:n { #1 }
}
\NewDocumentCommand{\mycommand}{ }
{
\tl_use:N \g_stephen_list_tl
}
\tl_new:N \g_stephen_list_tl
\cs_new_protected:Npn \stephen_mytrdc:n #1
{
\stephen_appto_mycommand:ffn { \arabic{mycounter} } { \thepage } { #1 }
}
\cs_new_protected:Npn \stephen_appto_mycommand:nnn #1 #2 #3
{
\tl_gput_right:Nn \g_stephen_list_tl { \mysndc { #1 } { #3 } { #2 } }
}
\cs_generate_variant:Nn \stephen_appto_mycommand:nnn { ff }
\ExplSyntaxOff
\begin{document}
\setcounter{mycounter}{7}
x
\mytrdc{8}
\newpage
\setcounter{mycounter}{4}
y
\mytrdc{42}
\expandafter\show\csname g_stephen_list_tl\endcsname
\end{document}
在实际文档中,你应该使用\mycommand
而不是\show
。参数的双重反转是为了提高效率。终端上的输出将是
> \g_stephen_list_tl=macro:
->\mysndc {7}{8}{1}\mysndc {4}{42}{2}.