插入宏

插入宏

偶尔我会尝试理解 TeX 的工作原理...到目前为止成功了,但有时我会设法定义一个宏。例如,

\def\appendto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}%

可以通过例如排版文本

\def\txt{}

\appendto{\txt}{Hello}
\appendto{\txt}{ }
\appendto{\txt}{world!}

%% Expand it.

\txt

那么我的问题是,如何定义相应的插入宏?相应的插入宏应该扩展为

你好世界!

当输入为

\def\txt{}
\insert{\txt}{world!}
\insert{\txt}{ }
\insert{\txt}{Hello}
\txt

答案1

基于宏观的方法

\def\prependto#1{%
  \expandafter\prependtohelper\expandafter{#1}#1%
}
\long\def\prependtohelper#1#2#3{%
  % #1: contents of macro
  % #2: macro
  % #3: text for prepending
  \def#2{#3#1}%
}

% Testing
\def\txt{}
\prependto{\txt}{world!}
\prependto{\txt}{ }
\prependto{\txt}{Hello}

\immediate\write16{\meaning\txt}

\csname @@end\endcsname\end

评论:

  • 我添加了\long\prependhelper,用于读取插入的文本。然后文本可能还包含\par标记(空行、整个段落)。

  • 基于宏的方法的缺点是#token 会带来麻烦。以下基于 token 或 e-TeX 的方法解决了这个问题。

基于代币的方法

\def\space{ }% already defined in plain TeX and LaTeX

\long\def\prependto#1#2{%
  \begingroup
    \toks0={#2}%
    \toks0=\expandafter{\the\toks0\expandafter\space#1}%
    \xdef\prependhelper{\the\toks0}%
  \endgroup
  \let#1\prependhelper
}

\def\txt{}
\prependto{\txt}{world!}
\prependto{\txt}{ }
\prependto{\txt}{Hello}

\immediate\write16{\meaning\txt}

\csname @@end\endcsname\end

评论:

  • \edef如果在(或全局工作)中扩展令牌寄存器,则有一个特殊之处\xdef。令牌寄存器是输出,但输出令牌不会进一步扩展。

  • 该组的目的是将令牌寄存器 0 的更改保持在本地。全局宏\prependhelper将宏的新定义传输到组外。

  • 宏定义使用了一些扩展技巧。在标记寄存器赋值看到左花括号之前,它仍然会扩展宏,因此\expandafter可以转到那里,而不需要从赋值之前开始。

  • \toks0\expandafter\space是另一个扩展技巧。如果 TeX 解析数字,则它会扩展直到找到非数字。如果空格作为结尾,则忽略该空格。

如果可以使用临时寄存器(如)\toks@,则定义可以变得更小(使用\makeatletter\catcode`@=11):

\long\def\prependto#1#2{%
  \toks@={#2}%
  \toks@\expandafter{\the\expandafter\toks@ #1}%
}

基于 e-TeX 的方法

e-TeX 扩展提供了\unexpanded,可用于避免使用令牌寄存器的规避:

\long\def\prependto#1#2{%
  \edef#1{\unexpanded{#2}\unexpanded\expandafter{#1}}%
}

\def\txt{}
\prependto{\txt}{world!}
\prependto{\txt}{ }
\prependto{\txt}{Hello}

\immediate\write16{\meaning\txt}

\csname @@end\endcsname\end

评论:

  • 再次,\expandafterbefore\unexpanded可以被删除,因为 e-TeX 会一直扩展 after\unexpanded直到找到打开的花括号。

相关内容