\string 命令行为 - Plain TeX

\string 命令行为 - Plain TeX

我想学习 Plain TeX,我正在阅读 Knuth 的《The TeXBook》。在第 7 章中,Knuth 讨论了该\string命令以及它如何将控制序列转换为字符标记列表。

为什么我打字时 \string\TeX得到"TeX,但当我写时却{\tt \string\TeX}得到\TeX

我猜想这与有关\escapechar,因为当我改变该控制序列时,输出也发生了变化:

\escapechar=`^
\string\TeX

它产生^TeX

答案1

的 ASCII 码\是 92,这也是 TeX 反斜杠的内部代码。现在看一下 TeXbook 的附录 F(F就像字体表一样)。在那里你可以看到打字机字体cmtt10确实\在位置 92 有一个位置(八进制表示为 ´134),而标准文本字体在该位置cmr10有一个引号。后者的原因是,在标准文本中,你经常需要引号,但几乎不需要反斜杠。

如果你想自己制作字体表,请使用以下代码(感谢史蒂芬·柯特维茨谢谢您的建议!):

\documentclass{article}
\addtolength{\textheight}{1cm}
\usepackage{fonttable}
\begin{document}
\fonttable{cmr10}
\fonttable{cmtt10}
\end{document}

字体表

答案2

Hendrik 的回答很棒。不过,请允许我\string再详细阐述\escapechar一下:

就像您所说的那样,该\string原语将控制序列转换为字符标记列表1。它还适用于其他标记并将它们转换为字符串表示形式。这里有两点值得注意:除空格外的所有字符都返回为类别代码(catcode) 12“其他”,即使它们之前来自 catcode 11“字母”。如果控制序列包含空格(可能包含\csname .. \endcsname),则它们仍然具有 catcode 10“空格”。此 catcode 更改对这些字符的排版或 ing 没有影响\write

其次,TeX 不会将控制序列中的反斜杠与每个控制序列名称一起存储。反斜杠仅在将控制序列标记为一个时才需要,一旦该控制序列被标记化,就不再需要它了。而且反斜杠并不是硬连线到 TeX 中的。每个带有 catcode 0“转义字符”的字符都可以使用。但是默认情况下,反斜杠是唯一一个具有此 catcode 的字符。由于 TeX 不会存储用于每个特定控制序列的转义字符,因此当它必须将控制序列重新转换为字符串时,它需要被告知如何表示它。这是使用\escapechar寄存器2来完成的,该寄存器保存所用字符的 ASCII 编号。默认情况下,它是 92,这是反斜杠的编号。这个寄存器可以随意更改。如果它包含负数,则根本不会产生任何转义字符\string。这个事实经常被 (La)TeX 代码使用,它喜欢只获取宏名称。Hendrik 是否已经在他的精彩回答中写道,您需要确保当前使用的字体中存在转义字符。通常,使用 tt 字体是正确的。

因此,例如\escapechar=`\A\catcode`\|=0 |string|foo将输出Afoo,而不是\foo|foo。在 catcode 更改之后,TeX 不会在这里关心您是否使用|\,您可以根据需要混合它们(请注意,现在\\可以写成 ,|\但不能写成 ,||因为第二个反斜杠不是转义字符)。您也不必强制\escapechar使用 catcode 0 的字符。


1)Knuth,TeXBook,第 40 页,第 7 章第 1 段:TEX 如何读取你输入的内容.2
Knuth,TeXBook,第 40 页,第 7 章第 6 段:TEX 如何读取你输入的内容

答案3

理论

它是如何\string工作的?有各种各样的情况,但首先我们必须意识到,这是一个 TeX 的原始命令,它只查看下一个标记无需扩大. 此查找发生标记化过程,可以以各种方式转换输入。

因此,我们感兴趣的是\string<token>

  1. 如果<token>是除 10 之外的任意类别代码的字符(包括活动字符),则扩展与类别代码 12 相同。但请注意, 不能<token>属于类别 0、9、14 或 15,因为这样的字符永远不会到达发生扩展的“口”。

  2. 如果<token>是类别代码 10 的字符,则扩展为 (32,10) 对,即类别代码 10 的普通空格标记。

  3. 如果<token>是代码为 32 且具有任意类别代码的字符,则扩展名为 (32,10) 对,与前面的情况相同。

  4. 如果<token>是控制序列,则 的扩展\string<token>是控制序列的名称,前面是字符代码等于 的当前值的字符\escapechar。此扩展中的所有字符都将具有类别代码 12,但空格除外,这些空格被规范化为字符代码 32 和类别代码 10 的正常空格标记。控制序列不需要定义,也不会存储在哈希表中。

  5. 但是,如果 的值\escapechar小于 0 或大于 255,则返回的字符串开头不会添加任何字符。0x1FFFFF对于 XeTeX 和 LuaTeX,上限为 2097151,即 。

例子

  1. 输入

    \edef\x{\string a}\ifcat\x a\message{11}\else\message{12}\fi
    

    将返回 12

  2. 输入

    \catcode`?=10 \def\temp{?}\edef\x{\expandafter\string\temp}\show\x
    

    将返回

    > \x=macro:
    -> .
    
  3. 输入

    \catcode`\ =12 \edef\x{\string }%
    \ifcat\x\space\message{10}\else\message{12}\fi
    

    将返回 10

  4. 输入

    \edef\x{\string\foo}\show\x
    

    将返回

    > \x=macro:
    ->\foo.
    

    o(和之间缺少空格.表明这\foo不是控制序列)。相反\escapechar=`A \edef\x{\string\foo}\show\x将返回

    > Ax=macro:
    ->Afoo.
    
  5. 输入

    \escapechar=-1 \edef\x{\string\foo}\show\x
    

    将返回

    > \x=macro:
    ->foo.
    

    ( 之前没有任何字符foo

印刷

关于 的打印输出的问题\string\foo则是另一回事;如果说\char`\\,TeX 将打印当前字体的 92 号位置中的任何字符,该字符可能是反斜杠,也可能不是。它不在标准的 Plain TeX 字体 中\tenrmcmr10而是在 中cmtt10。打印 产生的字符串时也会发生同样的情况\string\foo

答案4

这里提到的问题与\stringTeX 原始行为无关,但与以下事实有关:Computer modern 文本字体不遵守 ASCII 编码(打字机 Computer Modern 字体除外,它们遵守 ASCII)。ASCII 的例外情况有 7 个位置:

  • <打印为 ¡
  • >打印为 ¿
  • \打印为“
  • {打印为 –
  • |打印为 -
  • }打印为“
  • $在字体的草书变体中打印为 £

此外,字符\{}$在纯 TeX 中(以及其他格式中)都有特殊的类别代码,因此如果您想打印它们,不能简单地写下来。

在这七次出现中不尊重 ASCII 的原因是:使用的 7 位(128 个插槽)Computer Modern 字体中的插槽很少,并且需要实现 ASCII 表中未包含的常见印刷字符。为什么 Knuth 不使用 8 位字体(256 个插槽)?它们在 TeX 内存中占用更多空间,并且 Knuth 需要预加载来自 Computer Modern 系列的许多字体。在 TeX 诞生的那些日子里,计算机的内存非常有限。人们认为<|>只会在数学模式下使用(其中字体和插槽选择由与文本字体不同的原则完成),并且应该使用特殊的宏来打印 \ 、 { 、 } 、 $ 。

现在,这个问题只属于 TeX 历史,因为我们通常不使用 Computer Modern 字体,而是使用 Unicode 字体(1114111 个可用插槽)。如果有人遇到此处讨论的这个问题,则意味着他/她沉浸在历史软件(40 年前)的研究中,而不使用当前的现代 TeX。

相关内容