类别代码是什么?

类别代码是什么?

这个问题,我想问一个更普遍的问题:

什么是类别代码?通过更改它们我能实现什么?

答案1

当 TeX 解析输入时,它会为每个读取的字符分配一个类别代码。TeX 随后如何解释输入取决于字符及其类别代码。程序员可以设置 16 个类别代码,外加一个特殊的内部代码。16 个标准代码从 0 向上编号。类别代码 0 用于转义字符,通常是\。其余的如下(附典型示例):

  1. 开始组:{
  2. 结束组:}
  3. 数学转变:$
  4. 结盟:&
  5. 行结束
  6. 宏的参数:#
  7. 数学上标:^
  8. 数学下标:_
  9. 完全被忽视
  10. 空间
  11. 字母:字母表。
  12. “其他”字符 - 其他所有字符:.,,,1:ETC。
  13. 活动字符-被解释为控制序列:~
  14. 评论开始:%
  15. 输入无效:[DEL]

现在,当 TeX 读取输入时,每个字符都与一个类别代码相关联以生成标记。因此,如果输入为

$ 1^{23}_a $

TeX 内容如下:

  • 一个数学移位标记,进入数学模式
  • 空格,在数学模式下会被忽略
  • 一个“其他”标记1,在这里只是简单地排版
  • 数学上标标记,这意味着下一个项目将被上标
  • 一个 begin-group 标记,
  • “其他”标记23,在组完成之前无法排版
  • close-group 标记},允许 TeX 排版上标
  • 数学下标标记,将下一个项目移动到下标位置
  • 字母a,没有特殊含义,排版
  • 空格,再次被忽略
  • 一个数学移位标记,然后返回水平模式

当 TeX 决定什么是控制序列,什么不是控制序列时,类别代码通常很重要。如果只使用字母表作为“字母”,则

\hello@

是控制序列,\hello后面跟着“其他”标记@。另一方面,如果我制作@一个字母

\catcode`\@=11\relax
\hello@

然后 TeX 会查找名为 的宏\hello@。这通常用于 TeX 代码中,以将“代码”宏与“用户”宏隔离开来。因此,您会发现诸如 这样的编程宏\@for。如果不更改类别代码,这实际上是“隐藏”的。这样做的目的是“保护用户免受自身攻击”:如果您甚至无法获得代码,就很难破解代码!

~使用类别代码可以实现许多效果。最明显的效果是TeX 世界中普遍使用的不间断空格。这是因为~的类别代码为 13,因此是“活动的”。当 TeX 读取 时~,它会以与宏相同的方式查找 的定义~。在这些情况下,这比使用宏方便得多。

我们可以使用不同的类别代码来创建“私有”代码区域。例如,普通 TeX 和 LaTeX2e 使用@作为一个额外的“字母”,而 LaTeX3 使用:_。当两者一起使用时(如目前),这有效地将内部 LaTeX3 代码与 LaTeX2e 隔离开来。

逐字材料是另一个类别代码至关重要的领域(如果很复杂的话!)。您不能将逐字材料嵌套在其他任何内容中的原因是,一旦 TeX 分配了类别代码,它就只能部分可逆。任何“忽略”或“注释”的内容都会被丢弃:您无法将其恢复。(使用 e-TeX,您重新分配类别代码,但任何已经消失的东西都会保持“丢失”状态。


(感兴趣的人请注意)“特殊”类别代码为 16,除其他用途外,还用于测试\ifcat。在这种情况下,它被分配给不可扩展的控制序列,以便它们不匹配除其他不可扩展的控制序列之外的任何其他内容。

答案2

Knuth 决定保留一些字符用于常见任务,例如启动数学模式或表示上标和下标,而不是定义基本命令。还有其他需求:分组、表示宏参数,最重要的是,为了表达命令而进行转义。

类别代码共有 16 个:

 0 = escape
 1 = group start
 2 = group end
 3 = math shift
 4 = alignment tab
 5 = end of line
 6 = parameter
 7 = superscript
 8 = subscript
 9 = ignored character
10 = space
11 = letter
12 = other character
13 = active character
14 = comment
15 = invalid character

通常只有一个字符具有类别 0 至 8

\ { } $ & ^^M # ^ _

(^^M 表示 TeX 放在所有输入行末尾的不可见字符,用于更改可能存在的系统相关字符);唯一性不是必需的,但是是首选:为什么要有两个不同的转义字符以相同的方式起作用?(见下文。)

类别 10 是空格,也是<TAB>字符,与空格序列没有区别;类别 10 字符在行首被忽略。类别 5 非常特殊:它会转换为空格,除非它后面跟着另一个类别 5 字符,此时它成为命令\par(这是允许留下一个空白行来结束段落的技巧)。通常,任何连续的类别 10 字符序列都会减少为仅一个,无论它们是空格、制表符还是转换后的行尾字符都没有关系。

所有字母都有第 11 类和标点符号,例如?())属于第 12 类;这是因为命令名称可以是任何字母序列(最好是第 11 类字符)或非 11 类别字符,前面是 0 类别字符。当不属于命令名称时,可以打印 11 类别和 12 类别字符;其他所有类别代码并非如此。但是,类别代码 11 或 12 字符也可能不会显示在打印中,因为它在处理过程中被丢弃(例如,关键字或软件包选项、软件包或文件名等)。

之所以将类别 9 和 15 放入 TeX,是因为其中存在“危险”字符(ASCII“null”和 ASCII“delete”),可能会被编辑器误解。实际上,类别 9 还有其他用途:在 LaTeX3 样式文件中,空格被指定为类别 9,以帮助程序员避免可怕的“虚假空格”。

第 14 类是众所周知的%,它引入注释并让 TeX 忽略行中跟在它后面的所有内容(包括行尾)。

第 13 类非常特殊;Plain TeX 和 LaTeX 内核仅使用一个积极的字符,即~;活动字符被视为命令,必须具有定义才能使用;LaTeX 定义是

\catcode`~=13
\def~{\nobreakspace{}}

这样输入~就和书写 一样了\nobreakspace{}。LaTeX“inputenc”包还使用其他活动字符,例如,ü被翻译成\"u

当我们想要排版逐字TeX 代码中,许多特殊字符被分配了类别代码 12;但是当我们输入 时\verb+\xyz+,LaTeX 会读取\verb并准备所有内容进行逐字排版并启动一个组;第一个+被吞并并被分配到类别 2,因此当它找到第二个时,+该组终止并且所有分配都恢复为正常分配(包括对 的第 2 类别分配+):这有点神奇,但它有效,只要\verb+\xyz+不出现在命令的参数中。

这是一个问题:当 TeX 扫描命令的参数时,它冻结类别代码:当一个字符进入 TeX 时,它会转换成一对(category code, character code)不再是原始字符的字符,因此类别代码分配不能再修改(嗯,实际上不是,有\scantokens,但这需要很长的讨论)。

LaTeX 命令\makeatletter\makeatother通过更改 的类别代码@(通常为 12)来工作;第一个命令将其放入类别 11,以便它可以出现在命令名称中,第二个命令恢复此分配。但如何

\makeatletter
\newcommand{\xyz}{...\@xyz...}
\makeatother

能行吗?有人可能会认为 TeX 在扩展时\xyz会找到“非法”的命令名\@xyz。但事实并非如此:就像一个简单的字符会转换成一对数字一样,当 TeX 扫描它时,命令名会变成一个象征性标记,命令的内部表示,与字符及其类别代码无关。

如果我们将类别代码 0 分配给|,我们可以输入\LaTeX|LaTeX:它们的含义完全相同。但是,让不同的字符共享相同的类别代码 4 可能有助于在表格中的小数点分隔符处对齐小数。如果我们分配.类别代码 4,我们可以将小数输入为 ,123.456而 LaTeX 会将其解释为123&456产生表格单元格对于最终用户来说是一个整体;不过,在表格列结构的定义中需要一些技巧。

答案3

这不是一个简单的话题,我只能请您参考 TeXBook 来了解更多详细信息,但这里有一个简短的概述。

TeX 从文件读取的每个字符都有两个与之关联的数字。一个“字符代码”和一个“类别代码”。TeX 不认识字形 - 只认识数字 - 这是它的优势之一。您可以将字体表视为查找列表。如果您给它一个数字,TeX 将查看列表并打印恰好位于该位置的字形。

第二个数字是“类别代码”。TeX 使用它来智能地解析输入。例如,TeX 需要知道{文档的某个部分是否出现了左花括号,以便它可以查找结束括号等等。当然,这可以是硬编码的,但 Knuth 选择将其抽象化,这样任何字符,只要它有适当的类别代码,都可以使用。

考虑一下您可能希望用方括号替换花括号 [],这可以通过以下简单的代码实现:

\catcode `[=1
\catcode `]=2

\def\test[This is a test]
\bye

如果不进行任何更改就尝试catcode,它将会因失控定义错误而失败。

类似地,\可以重新定义反斜杠字符以用于逐字文本。

\catcode `[=1
\catcode `]=2
\def\test[This is a test]
\catcode `*=0
 *def*test[This is another test]
 *test
 \bye

在最后一个例子中,\您可以输入*。通过 pdfTeX 运行 MWE。作者实际上不需要它们,但它们对于软件包开发人员来说非常有价值。

答案4

这里已经有很好的答案了,所以让我仅展示一个小例子,说明通过更改 catcode 可以做什么。假设您在像和这样的表中有数字,12.3并且8.45您想将它们全部填充到相同的宽度,以使它们排列整齐。 (让我们暂时忽略有几种方法。)您可以通过0在之后12.3和之前添加不可见的来做到这一点8.45。不可见的由(或)0提供。现在,使用它来输入有点不愉快,因为它会弄乱您的源代码布局。但您可以使本地活动并赋予它含义:\phantom{0}\phantom0_\phantom0

\catcode`_=\active
\def_{\phantom0}

现在您可以在表格中使用12.3_和。您也可以使用其他字符,例如。由于在数学模式下用于下标,因此这仅在您不需要下标且上述定义处于活动状态时才有效。_8.45!_

相关内容