如何将宏扩展移到当前半组之外,而无需全局定义宏?

如何将宏扩展移到当前半组之外,而无需全局定义宏?

我编写了一个宏,用于计算用 s 分隔的线条\measureHbox{}的高度和宽度:\hbox\break

\long\def\measureHbox#1{%
  \begingroup
    \def\break{\noexpand\my@cr}%
    \protected@edef\@argi{#1}%
    \@tempdima\z@%% width
    \@tempdimb\z@%% height+depth
    \long\def\mesure@line ##1\my@cr##2\@nil{%
      \if!##1!\else
        \setbox\@tempboxa\hbox{##1}%
        \ifdim\wd\@tempboxa>\@tempdima\relax
          \@tempdima=\wd\@tempboxa
        \fi
        \advance\@tempdimb\ht\@tempboxa
        \advance\@tempdimb\dp\@tempboxa
        \if!##2!\else
          \mesure@line##2\@nil
        \fi
      \fi
    }%
    \expandafter\mesure@line\@argi\my@cr\@nil
    \edef\mytemp{%
      \noexpand\setDimension{Width}{\the\@tempdima}%
      \noexpand\setDimension{Height}{\the\@tempdimb}%
    }%
    \message{^^J==DEBUG>\meaning\mytemp}%
    \expandafter\mytemp
  \endgroup
}

该宏\setDimension定义如下:

\def\setDimension#1#2{\expandafter\edef\csname my#1\endcsname{#2}}

这一切都很好,除了我需要改变 measureHbox 定义中使用的所有宏本地(例如\break)但我需要半群“之外”的结果,例如:

\documentclass[english]{minimal}

\makeatletter
%% definition of \measureHbox here
\parindent\z@
\parskip\z@
\rightskip\@flushglue
%% definition of \setDimension here
\def\mytemp{DO NOT CHANGE ME GLOBALLY!!}
\makeatother

\setDimension{Width}{5pt}
\setDimension{Height}{5pt}

\begin{document}
{\bfseries Before group:}\par
Original width: \myWidth\par              % is: 5pt
Original height: \myHeight\par            % is: 5pt
\mytemp                                   % original definition

\vskip\baselineskip
\bgroup
  {\bfseries In group:}\par
  \measureHbox{This is a\break breaking box}\par
  Measured width: \myWidth\par            % should be: 56.6946pt
  Measured height: \myHeight\par          % should be: 15.83333pt
  \mytemp\par\vskip\baselineskip          % should print nothing inside this group
\egroup

{\bfseries After group:}\par
Original width: \myWidth\par              % should be 5pt again
Original height: \myHeight\par            % should be 5pt again
\mytemp                                   % original definition again
\end{document}

对于嵌入宏的代码来说,重要的是,此宏定义中使用的所有宏都不会全局更改。我的天真方法是在定义的最后两行\mytemp之后展开宏:\endgroup\measureHbox

    \expandafter\mytemp
  \endgroup

但那不管用,也不管用

    \aftergroup\mytemp
  \endgroup

我的问题是: 有没有办法\mytemp在 的定义中将 的展开式“移”到半群之外\measureHbox

为了完整起见,这里是粘合在一起的完整“最小”示例:

\documentclass[english]{minimal}

\makeatletter
\long\def\measureHbox#1{%
  Original Box:\par\vskip\baselineskip#1\par\vskip\baselineskip
  \begingroup
    \def\break{\noexpand\my@cr}%
    \protected@edef\@argi{#1}%
    \@tempdima\z@%% width
    \@tempdimb\z@%% height+depth
    \long\def\mesure@line ##1\my@cr##2\@nil{%
      \if!##1!\else
        \setbox\@tempboxa\hbox{##1}%
        \ifdim\wd\@tempboxa>\@tempdima\relax
          \@tempdima=\wd\@tempboxa
        \fi
        \advance\@tempdimb\ht\@tempboxa
        \advance\@tempdimb\dp\@tempboxa
        \if!##2!\else
          \mesure@line##2\@nil
        \fi
      \fi
    }%
    \expandafter\mesure@line\@argi\my@cr\@nil
    \edef\mytemp{%
      \noexpand\setDimension{Width}{\the\@tempdima}%
      \noexpand\setDimension{Height}{\the\@tempdimb}%
    }%
    \message{^^J==DEBUG>\meaning\mytemp}%
    \expandafter\mytemp
  \endgroup
}
\parindent\z@
\parskip\z@
\rightskip\@flushglue
\def\setDimension#1#2{\expandafter\edef\csname my#1\endcsname{#2}}
\def\mytemp{DO NOT CHANGE ME GLOBALLY!!}
\makeatother

\setDimension{Width}{5pt}
\setDimension{Height}{5pt}

\begin{document}
{\bfseries Before group:}\par
Original width: \myWidth\par
Original height: \myHeight\par
\mytemp

\vskip\baselineskip
\bgroup
  {\bfseries In group:}\par
  \measureHbox{This is a\break breaking box}\par
  Measured width: \myWidth\par
  Measured height: \myHeight\par
  \mytemp\par\vskip\baselineskip
\egroup

{\bfseries After group:}\par
Original width: \myWidth\par
Original height: \myHeight\par
\mytemp
\end{document}

答案1

\edef\mytemp{%
      \noexpand\setDimension{Width}{\the\@tempdima}%
      \noexpand\setDimension{Height}{\the\@tempdimb}%
    }%
    \message{^^J==DEBUG>\meaning\mytemp}%
    \expandafter\mytemp
  \endgroup

由于不可扩展,\expandafter因此不执行任何操作,但你可以执行\endgroup

\edef\mytemp{\endgroup
      \noexpand\setDimension{Width}{\the\@tempdima}%
      \noexpand\setDimension{Height}{\the\@tempdimb}%
    }%
    \message{^^J==DEBUG>\meaning\mytemp}%
    \mytemp

因此您的寄存器在组内得到扩展,但组在替换文本的开头结束。

或者

\edef\mytemp{%
      \noexpand\setDimension{Width}{\the\@tempdima}%
      \noexpand\setDimension{Height}{\the\@tempdimb}%
    }%
    \message{^^J==DEBUG>\meaning\mytemp}%
    \expandafter\endgroup
\mytemp
  

所以\mytemp在组结束之前就扩大了。

相关内容