如何以纯文本实现 \text?

如何以纯文本实现 \text?

我正在尝试实现 LaTeX 命令\text{},使数学模式下的文本表现得就像在数学模式之外一样。

我目前的尝试如下。

\def\text#1{\begingroup\rm\testing#1\endtest}
{\escapechar=-1\xdef\endtest{\string\\endtest}}
\def\testing#1#2{\ifx#2\endtest\let\next=\endgroup\else\let\next=\testing\fi%
{\catcode`\|=10\ifcat#1|\hskip.5em\else#1\fi}\next #2}

这至少有两个缺点:首先,它会\endtest在文本后产生;其次,文本中没有空格。

例如,

\text{example haha}

给出

examplehaha\endtest.

我没有什么办法可以摆脱它\endtest在文本中并留下空间。


对于像我这样的新手来说,任何帮助或参考都非常感谢。提前致谢。

答案1

很简单,你只需要使用

\hbox{hello world}

amsmath(或更确切地说amstext)中\text被定义为使用\mathchoice并使用不同大小的文本是下标等,但是纯文本没有真正的字体大小更改命令,因此默认情况下,您无法执行任何类似的操作。如果您限制为,\rm那么该字体在中设置为不同的大小,\fam0因此您可以执行

\def\textrm#1{\mathchoice
{\hbox{\the\textfont0 #1}}
{\hbox{\the\textfont0 #1}}
{\hbox{\the\scriptfont0 #1}}
{\hbox{\the\scriptscriptfont0 #1}}}


$$\textrm{one two} x^{\textrm{one two}^{\textrm{one two}}}$$

\bye

在此处输入图片描述

答案2

您可以使用opmac(如果您坚持使用纯 TeX,我推荐您使用):

\input opmac

\def\text#1{%
  \relax
  \ifmmode
    \mathchoice
      {\hbox{#1}}
      {\hbox{#1}}
      {\hbox{\typoscale[700/]\relax#1}}
      {\hbox{\typoscale[500/]\relax#1}}%
  \else
    \hbox{#1}%
  \fi
}
$$
a\text{a}_{a\text{a}_{a\text{a}}}
$$
$$
a+b=b+a\text{ is a {\it nice\/} property}
$$
$$
\scriptstyle a+b=b+a\text{ is a {\it nice\/} property}
$$
$$
\scriptscriptstyle a+b=b+a\text{ is a {\it nice\/} property}
$$

\bye

在此处输入图片描述


只是为了好玩,让我尝试描述一下你的宏的作用。

\def\text#1{\begingroup\rm\testing#1\endtest}
{\escapechar=-1\xdef\endtest{\string\\endtest}}
\def\testing#1#2{\ifx#2\endtest\let\next=\endgroup\else\let\next=\testing\fi%
{\catcode`\|=10\ifcat#1|\hskip.5em\else#1\fi}\next #2}

第一个\text被定义为吸收其参数并返回标记列表

\begingroup\rm\testing<argument>\endtesting

该宏\testing被定义为具有两个参数。如果第二个参数是\endtest,则控制序列\next被定义为,\endgroup否则被定义为\testing,这将启动递归。然后

{\catcode`\|=10\ifcat#1|\hskip.5em\else#1\fi}

完成,其中#1代表 之后的第一个标记(或括号组的内容)\testing。测试\ifcat#1|不是如果是空格则成功,#1原因有两个:当 TeX 寻找未分隔的参数时,空格会被忽略,#1因此绝不是空格标记;第二个原因,当 是类别代码 12 的单个标记时,测试将成功,这是定义时#1的类别代码。|

因此,如果后面跟着诸如 (catcode 12) 之类的字符.(并且忽略该字符),则会得到一个空格,否则,如果该字符是字母,则会得到该字符。如果#1是括号组的内容,那么,任何事情都可能发生。\next执行 Finally,然后#2重新插入。这就是“endtest”出现在末尾的原因。

回想一下,当一个论点被吸收时,类别代码会被冻结,因此设置\catcode`\|=10根本不会执行任何操作。

通过添加两个终止符,可以获得没有“终止”问题的递归。

% generic terminators
\def\TerminatorA{\TerminatorA}
\def\TerminatorB{\TerminatorB}

\def\boldenas#1{\boldenasRecurse#1\TerminatorA\TerminatorB}
\def\boldenasRecurse#1#2#3\TerminatorB{%
  \boldenasDo{#1}%
  \ifx#2\TerminatorA
    \let\next\boldenasEnd
  \else
    \let\next\boldenasRecurse
  \fi
  \next#2#3\TerminatorB
}
\def\boldenasDo#1{%
  \ifx #1a%
    {\bf a}%
  \else
    #1%
  \fi
}
\def\boldenasEnd#1\TerminatorB{}


\boldenas{abracadabra}

\bye

这对于空值来说并不安全#1(毕竟我们是严格的普通 TeX 用户)。空格将被吞噬,原因我之前解释过,而支撑组将产生混乱。但是,嘿,我们在做理论!

请注意,\let可以避免以下指令:

% generic terminators
\def\TerminatorA{\TerminatorA}
\def\TerminatorB{\TerminatorB}
% syntactic sugar
\long\def\firstoftwo#1#2{#1}
\long\def\secondoftwo#1#2{#2}

\def\boldenas#1{\boldenasRecurse#1\TerminatorA\TerminatorB}
\def\boldenasRecurse#1#2#3\TerminatorB{%
  \boldenasDo{#1}%
  \ifx#2\TerminatorA
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  \boldenasEnd\boldenasRecurse#2#3\TerminatorB
}
\def\boldenasDo#1{%
  \ifx #1a%
    {\bf a}%
  \else
    #1%
  \fi
}
\def\boldenasEnd#1\TerminatorB{}


\boldenas{abracadabra}

\bye

相关内容