完成所有这些之后再进行扩张?

完成所有这些之后再进行扩张?

我经常发现自己需要扩展一些宏,这些宏的内容应该作为另一个命令的参数。通常的解决方案是调用一些\expandafter混合物以某种方式控制扩展,但我想知道(至少对于某些常见情况)是否存在更简单的方法。

举个例子,假设我想写如下内容

\somecommand{Some Argument}{\secondarg}

但我想扩大\secondarg 实际上正在尝试处理\somecommand

对于这种情况,是否可以定义一个命令以便

\expandafterallthat{\somecommand{Some Argument}}{\secondarg}

扩展为类似

\somecommand{SomeArgument}{Contents of secondarg macro}

答案1

这是由etextools以下提供的\expandnext

\usepackage{etextools}
\expandnext{\somecommand{Some Argument}}{\secondarg}

但是如果你只想扩展第二个参数,那么你可以使用双参数交换,这是我在我的一些包中使用的技巧:

\documentclass{article}
%% Implementation
\def\myswap#1#2{#2{#1}}

\def\expandafterallthat#1#2{%
    \expandafter\myswap\expandafter{#2}{#1}%
}
%%%%%%%%%%%%%%%%

% Test case:
%
\makeatletter
\def\somecommand#1#2{%
    \def\first{#1}%
    \@onelevel@sanitize\first
    \par\texttt{First argument: \first}%
    \def\second{#2}%
    \@onelevel@sanitize\second
    \par\texttt{Second argument: \second}%
}
\makeatother

\def\secondarg{\empty Some stuff\empty}

\begin{document}

\expandafterallthat{\somecommand{\empty Some Argument\empty}}{\secondarg}

\end{document}

这正确打印:(s\empty用于查看参数是否进一步扩展)

first argument: \empty Some Argument\empty
Second argument: \empty Some stuff\empty

答案2

不使用包进行编写

\documentclass{article}
\newcommand\expandafterallthat[2]{%
  \expandafter\expandafterallthataux\expandafter{\romannumeral -`0#2 }{#1}%
}
\newcommand\expandafterallthataux[2]{#2{#1}}
\newcommand\somecommand[2]{\detokenize{#1:::#2}}
\newcommand\secondarg{\thirdarg}
\newcommand\thirdarg{\fourtharg}
\newcommand\fourtharg{example}
\begin{document}
\expandafterallthat{\somecommand{Some Argument}}{\secondarg}

\end{document}

将多次扩展输入。(您没有说明是扩展#2一次还是多次。)


使用最新的引擎版本(MiKTeX 或即将推出的 TL'19),可以使用\expanded

\documentclass{article}
\newcommand\expandafterallthat[2]{%
  \expanded{\unexpanded{#1}{#2}}}
\newcommand\somecommand[2]{\detokenize{#1:::#2}}
\newcommand\secondarg{\thirdarg}
\newcommand\thirdarg{\fourtharg}
\newcommand\fourtharg{example}
\begin{document}
\expandafterallthat{\somecommand{Some Argument}}{\secondarg}
\end{document}

\expanded一直在 LuaTeX 中,因此即使没有最新更新的引擎,您也可以在那里进行测试。)

答案3

由于 Joseph 尚未提及expl3,因此让我来提及:LaTeX3 软件包包含一个用于扩展控制的模块。l3expan具体而言,这包括用于扩展命令参数的函数,其形式\exp_args:N...为点为字母,对应于应如何处理各种参数。

有许多字母在使用:n表示应不加修改地传递的括号组、o扩展一次、f从左侧完全扩展,在第一个不可扩展的标记处停止、x完全扩展整个标记,就像 中一样\edef。还有N表示应按原样传递的单个非括号标记、c表示应制成控制序列然后作为参数处理的文本N,以及V表示v变量(有关详细信息,请参阅 l3expan 文档)。

在这里,您想要扩展第二个参数一次,而保持第一个参数不变,因此您需要的变体是\exp_args:Nno:保持函数不变(N),第一个参数用括号括起来,不变(n),第二个参数扩展一次(o)。

\newcommand{\foo}[2]{\showtokens{#1... #2}}
\newcommand{\sometext}{Some text.}
\RequirePackage{expl3}
\ExplSyntaxOn
\exp_args:Nno \foo {\error} {\sometext}
\ExplSyntaxOff

答案4

functional包中,棘手的参数扩展可以用直观的函数组合来代替,这与其他编程语言类似,例如Lua

\documentclass{article}

\usepackage{functional}
\Functional{scoping=true} % make every function become a group

\begin{document}

\IgnoreSpacesOn
\PrgNewFunction \SomeFunction { m m m } {
  \TlLog {#1}
  \TlLog {#2}
  \TlLog {#3}
}
\IgnoreSpacesOff

\newcommand\secondarg{Second Argument}
\newcommand\thirdarg{Third Argument}

\SomeFunction{First Argument}{\Value\secondarg}{\Value\thirdarg}

\end{document}

上面的代码中,\Value是一个预定义的函数。日志文件中的结果如下:

> First Argument.
> Second Argument.
> Third Argument.

相关内容