如何将宏的最终扩展捕获为字符串?

如何将宏的最终扩展捕获为字符串?

我有一个宏\a。我想定义一个宏\b,其替换文本T将满足以下要求:

  1. 每个 token 的 catcodeT都在 10-12 范围内。
  2. 忽略 catcodes,T逐个标记都等于\a的最终扩展。

例如,

\def\z{12pt}%
\def\a{\noindent\fontsize{10pt}{\z}\selectfont}%
\def\b{???}%
\b

应排版:

\noindent\fontsize{10pt}{12pt}\selectfont

如果这不可能,也可以,如果\b扩大一切递归地,直到没有什么可以扩展为止。

最后,下面的例子也足够好了:

\def\a{\noindent\fontsize{10pt}{\a}\selectfont}%
\def\b{???}%
\b

应排版:

\noindent\fontsize{10pt}{\a}\selectfont

答案1

不扩展和\a,而是\meaning

\documentclass{article}
\begin{document}
\def\z{12pt}%
\def\a{\noindent\fontsize{10pt}{\z}\selectfont}%
\makeatletter
\edef\b{\expandafter\strip@prefix\meaning\a}
\makeatother
\texttt{\b}
\end{document}

结果

命令名称后的空格由 TeX 插入。

使用 e-TeX 的 \detokenize 的变体:

\edef\b{\detokenize\expandafter{\a}}

在这两种情况下,定义文本中的标记\b具有类别代码 12(其他),而空格具有类别代码 10(空格)。


如果知道 的内容\a或多或少,则可以通过将不应扩展的宏重新定义为 的含义来防止扩展\relax

\documentclass{article}
\begin{document}
\def\z{12pt}%
\def\a{\noindent\fontsize{10pt}{\z}\selectfont}%

\begingroup
  \let\fontsize\relax
  \let\selectfont\relax
  \edef\x{\a}
  \xdef\b{\detokenize\expandafter{\x}}
\endgroup
\texttt{\b}
\end{document}

结果

的完全展开\a仅适用于某些宏,其结果或多或少有用:

\documentclass{article}
\begin{document}
\def\z{12pt}%
\def\a{\noindent\fontsize{10pt}{\z}\selectfont}%

\edef\tmp{\a}
\edef\b{\detokenize\expandafter{\tmp}}
\endgroup
\texttt{\b}
\end{document}

结果

microtype例如,添加包将得到一个\a通过以下方式硬扩展中断的宏\edef

! Argument of \MT@res@a has an extra }.
<inserted text>
                \par
l.7 \edef\tmp{\a}

LaTeX 的保护机制可供较软的 所用\protected@edef。然后, 定义的命令\DeclareRobustCommands和 带有可选参数的命令不会扩展太多:

\documentclass{article}
\usepackage{microtype}
\begin{document}
\def\z{12pt}%
\def\a{\noindent\fontsize{10pt}{\z}\selectfont}%

\makeatletter
\protected@edef\tmp{\a}
\makeatother
\edef\b{\detokenize\expandafter{\tmp}}
\texttt{\b}
\end{document}

结果

相关内容