1

I have a macro \a. I'd like to define a macro \b, whose replacement text, T, will satisfy the following requirements:

  1. The catcode of every token of T is in the range 10-12.
  2. Ignoring catcodes, T is token-by-token equal to \a's ultimate expansion.

For instance,

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

should typeset:

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

If this is not possible, it will be OK, too, if \b expands everything recursively, until there's nothing more to expand.

Finally, the following example, too, will be good enough:

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

should typeset:

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

Evan Aad
  • 11,066

1 Answers1

8

Without expansion of \a and with \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}

Result

The spaces after command names are inserted by TeX.

Variant with e-TeX's \detokenize:

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

In both cases, the tokens in the definition text of \b have category code 12 (other) and the space has category code 10 (space).


If the contents of \a is more or less known, then the macros that should not be expanded can be prevented from expansion by redefining them to the meaning of \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}

Result

A full expansion of \a only works for some macros with more or less useful result:

\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}

Result

Adding package microtype, for example, will get a macro \a that breaks in a hard expansion by \edef:

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

LaTeX's protection mechanism can be used by the softer \protected@edef. Then, commands defined by \DeclareRobustCommands and commands with optional arguments are not expanded too much:

\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}

Result

Heiko Oberdiek
  • 271,626