取消保护(扩展) \protected 宏(或“命令名称后的空格”)

取消保护(扩展) \protected 宏(或“命令名称后的空格”)

我经常会遇到这样的情况,需要获取由包宏生成的一些文本作为字符串,例如:

我在这里遇到的一件事是尝试使用\typeout有问题的宏,并且通常会观察到和它的参数之间的空格\command(因此有标题);而且我通常会错误地认为这是一个字符串解析问题(例如,如何删除命令和其参数之间的空格),并花费大量时间进行毫无意义的战斗:)


编辑:澄清这一点:

  • 在第一个链接中:\lipsum[1]命令在 PDF 文档中输入“Lorem Ipsum...”;人们希望以某种方式在命令中获取“Lorem Ipsum...”的字符\temp,以便\typeout{\temp}将“Lorem Ipsum...”打印到终端并记录输出。
  • 在第二个链接中:\today来自isodatePDF 文档中的排版“2012 年 5 月 24 日”;同样,人们希望以某种方式在命令中获取“2012 年 5 月 24 日”的字符\temp,以便\typeout{\temp}将“2012 年 5 月 24 日”打印到终端并记录输出。

\edef我猜是否用于此目的并不是什么大问题;但据我所知,它是唯一可能合适的命令)


现在,我终于想出了一个可以证明这一点的 MWE,所以我想用更通用的术语来问这个问题——考虑:

\documentclass{minimal}

\def\doubleCommand#1#2{testing-#1-#2}

\protected\def\tmpcmd#1{teststring#1} % concatenate, no spaces


\begin{document}

\typeout{--Test:--\doubleCommand{A}{B}--}

\edef\initArg{12}
\edef\dcArg{\tmpcmd\initArg}

\typeout{--Args:--\initArg--\dcArg--}

\edef\myResult{\doubleCommand{\dcArg}{Verbatim}}
\edef\myResult{\detokenize\expandafter{\myResult}}

\typeout{--Out :--\myResult--}

This: \doubleCommand{\dcArg}{Verbatim}

\end{document}

现在,它可以正常工作,并按This: testing-teststring12-Verbatim预期排版“”。但是,如果我们查看终端日志输出pdflatex,我们会得到:

--Test:--testing-A-B--
--Args:--12--\tmpcmd 12--
--Out :--testing-\tmpcmd 12-Verbatim--

也就是说,\edef没有扩展\tmpcmd命令 - 而是打印其名称以及参数(值得注意的是,命令和第一个参数之间有一个空格:))。

但是,由于内容排版良好,显然可以在某个地方访问 - 而我希望将此内容作为变量中的“字符串”。为了显示这一点,我需要做的就是删除命令\protected,所以我有:

\def\tmpcmd#1{teststring#1} % concatenate, no spaces 

...然后终端日志显示:

--Test:--testing-A-B--
--Args:--12--teststring12--
--Out :--testing-teststring12-Verbatim--

...也就是说,命令输出(“ teststring12-Verbatim”)现在是“变量”(命令)中的“字符串”值。

现在,我很确定这样做有充分的理由\protected;但是,很多时候我只想获取已排版的数据。那么在这些情况下,是否有可以采用的策略?上面的链接表明没有,解决方案(如果可能)取决于给定包的命令及其实现...但是,我想要一种可以采用的方法,而无需更改包样式文件(比如说,\protected从我可能需要的各种宏中删除,即使没有进一步了解,我也知道这不是一个好主意)。

我已经猜到这种通用方法是不可用的 - 但有人能解释一下为什么吗(也许根据上述 MWE)?

非常感谢您的任何回答,
干杯!

答案1

大卫已经用一种方式解释了这一点,我将采取稍微不同的策略。

首先,发生了什么?当 e-TeX 发现受保护的宏时,它不会在 内展开它\edef\write以及一些类似情况,通常会彻底展开所有内容。这是为了确保您可以看到受保护的令牌在结果中。例如,

\protected\def\a{}
\typeout{%
  \a%
  b%
}

将显示,即使就 TeX 而言和\a b之间没有空格。这是因为替代方法是,因为我们看不到标记,所以会产生误导(它是否意味着后面跟着或不同的宏?)。\ab\ab\ab\ab

你可以利用受保护宏确实尊重的事实来“强制”扩展它\expandafter

\protected\def\a{b}
\edef\test{\expandafter\empty\a}
\show\a

用作\empty扩展之物,之后不会留下任何痕迹。

其次,为什么需要保护?TeX 中的某些操作在 中根本不起作用,\edef因为它们使用的 TeX 基元不是“可扩展的”。这里的经典操作是赋值(\def\let等等)。如果你尝试

\let\a\undefined
\def\b{a}
\edef\test{\let\a\b}

你不会发现\a最终定义为a。相反,你会得到一个错误:在这种情况下是 ' Undefined control sequence'。这是因为\let不可展开。所以 TeX 只是在 中“让它保持原样” \edef,并尝试扩展\a。这是不可能的,所以会出现错误。因此,一般来说,尝试扩展受保护的宏不是一个好主意。

答案2

\protected停止扩展,\edef并且\write(与 LaTeX 保护机制不同)一旦应用,就不太容易取消。这里很难知道你需要什么,因为你要求“字符串”,但 TeX 没有字符串。

你可以做

\makeatletter

\protected\def\foo#1{---{\large#1}---}


\edef\x{\expandafter\strip@prefix\meaning\foo}
\show\x

产生

> \x=macro:
->---{\large #1}---.
l.8 \show\x
        

但请\x注意不是在其定义中包含\large命令,它有 6 个标记\ l a r g e(加上其他标记---{}---)。

查看为什么你需要保护,比较

\documentclass{article}

\makeatletter

\def\foo#1{---{\large#1}---}


\edef\x{\foo 1}
\show\x

将脆弱的、不受保护的命令放入 edef 中会产生

! TeX capacity exceeded, sorry [input stack size=5000].
\@nomath ...e \@font@warning {Command \noexpand #1
                                                  invalid in math mode}\fi 
l.8 \edef\x{\foo 1
                  }
!  ==> Fatal error occurred, no output PDF file produced!




   

相关内容