这是对我的问题的一个间接的后续回答: ToC 和标签之类的东西如何在编译之间保存信息?
编辑:问题解决了,但原来的格式不正确。我已编辑问题以反映解决方案。
我对 latex 的很多扩展方面都比较熟悉,但我只知道如何避免特定宏扩展,或者在扩展过程中使用 \expandafter 跳过宏。但是有没有一种方法可以在定义宏时立即定义它,但不扩展该宏中的任何命令?让我举个例子。
假设我知道我将收到一些神秘的宏 \text、\texttwo、\textthree。我只知道它们包含文本和一些命令,但我不知道这些命令是什么。
我想编写一个宏,将神秘宏的内容转移到我拥有的新名称,这样我就可以更新之前的神秘宏。但我需要它立即执行此操作,这样,当我更新神秘宏时,我可以多次使用转移,在使用之间更新它,而不会在最后得到一堆重复的宏。因此,一些伪代码将是;
\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}
\newcommand{\transfer}[2]{%
\expandafter\let\csname#2\endcsname#1% \let works better than \edef
}%
\begin{document}
\transfer{\text}{newcomone}
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\transfer{\text}{newcomtwo}
\renewcommand{\text}{New Text Take three, but with \textthree}
\transfer{\text}{newcomthree}
\text
\newcomone
\newcomtwo
\newcomthree
\end{document}
理想情况下,我希望输出看起来像;
New Text Take three, but with Mysterious content here again and again
Mysterious content here
New Text Take two, but now include Mysterious content here again
New Text Take three, but with Mysterious content here again and again
在上面的例子中,我(最初)使用了 edef,但我不想直接使用 edef,因为那样会扩展 \newcomtwo 和 \newcomthree 中的命令。但我相信如果我使用 \def,这三个命令将完全相同。
现在,如果我知道传入的命令,我可以在相关命令前使用 \noexpand 或 \protect (即,编写类似 \renewcommand{\text}{New Text Take two, but now include \protect\texttwo} 的内容)但有没有办法在不需要访问神秘命令的情况下做到这一点?即,在我定义 \transfer 命令的级别上执行此操作?
答案1
已编辑问题的答案:
您可以简单地\let\newmacroname\oldmacroname \renewcommand\oldmacroname{...}
按照下面的说明使用。
\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\let\newcomthree\text
\text
\newcomone
\newcomtwo
\newcomthree
\end{document}
哪个是所需的输出。我不确定你为什么要定义\transfer
而不是仅仅使用\let
。你可能很快就会\let
直接使用 - 它可以提高代码的透明度,而且可以减少输入。有什么不喜欢的?
回答原始问题:
问题并不在于转换它们,而在于定义本身。
\let
复制宏。它不会扩展任何内容。它通常用于保存即将重新定义的宏定义,通常以利用原始定义的方式。
使用\let
,我们可以在每个点处复制\text
。使用 ,\show
我们可以在每个点处检查定义。
我们不能做的是使用 \newcomtwo
或者\newcomthree
因为它们的扩展现在会产生致命错误。但这并不是因为复制不准确。这是因为定义本身的概念存在问题。当您调用\newcomtwo
和时\newcomthree
,它们具有正确的定义。但我认为您还没有仔细考虑过这些定义会是什么,因为\text
现在有了全新的含义。
您可能的意思是 - 我不确定 -\text
应该使用 的原始定义。在这种情况下,您可以修补新命令。(但这\edef
可能是一个更简单的选择,所以这可能根本不是您的本意。)
\documentclass{article}
\usepackage{etoolbox}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo and \text}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\show\newcomone
\begin{verbatim}
\newcomone=\long macro:
->Mysterious content here.
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\show\newcomtwo
\begin{verbatim}
\newcomtwo=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\let\newcomthree\text
\show\newcomthree
\begin{verbatim}
\newcomthree=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\newcomone
\patchcmd\texttwo{\text}{\newcomone}{}{}
\patchcmd\textthree{\text}{\newcomone}{}{}
\newcomtwo
\newcomthree
\end{document}
\documentclass{article}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo and \text}
\begin{document}
\let\newcomone\text
\renewcommand{\text}{New Text Take two, but now include \texttwo}
\show\newcomone
\begin{verbatim}
\newcomone=\long macro:
->Mysterious content here.
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\let\newcomtwo\text
\renewcommand{\text}{New Text Take three, but with \textthree}
\show\newcomtwo
\begin{verbatim}
\newcomtwo=\long macro:
->New Text Take two, but now include \texttwo .
\end{verbatim}
\show\text
\begin{verbatim}
\text=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\let\newcomthree\text
\show\newcomthree
\begin{verbatim}
\newcomthree=\long macro:
->New Text Take three, but with \textthree .
\end{verbatim}
\newcomone
% \newcomtwo
% \newcomthree
\end{document}
答案2
现在所做的\transfer
是,通过第一串扩展,将#1
(即\text
)转换为 的宏替换\text
。第二轮扩展将转换\tmp
为\csname #2\endcsname
,而最后一轮扩展将分别转换\csname#2\endcsname
为\newcomone
和。\newcomtwo
\newcomthree
\detokenize
从我的调用结果可以看出,宏尚未完全展开。
\documentclass{article}
\usepackage[T1]{fontenc}
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here like \text}
\newcommand{\textthree}{Mysterious content here like \texttwo{} and \text}
\newcommand{\transfer}[2]{%
\def\tmp{\csname #2\endcsname}%
\expandafter\expandafter\expandafter\expandafter\expandafter%
\expandafter\expandafter\def\expandafter\tmp\expandafter{#1}%
}%
\begin{document}
\transfer{\text}{newcomone}
\newcommand{\textA}{New Text Take two, but now include \texttwo}
\transfer{\textA}{newcomtwo}
\newcommand{\textB}{New Text Take three, but with \textthree}
\transfer{\textB}{newcomthree}
\detokenize\expandafter{\newcomone}
\detokenize\expandafter{\newcomtwo}
\detokenize\expandafter{\newcomthree}
\bigskip
\newcomone
\newcomtwo
\newcomthree
\end{document}
我已经解决了 OP 的原始问题,但是根据他对\texttwo
和的修改定义\textthree
(由于它们不是递归的,所以更简单),
\newcommand{\text}{Mysterious content here}
\newcommand{\texttwo}{Mysterious content here again}
\newcommand{\textthree}{Mysterious content here again and again}
结果是