在 (La)TeX 中,您可以定义一个仅在数学模式下有效的活动字符,方法是为其指定一个数学代码"8000
并将相应的单字母宏带入范围。在 Xe(La)TeX 中,Unicode 字符似乎也适用:
\documentclass{article}
\usepackage{listings}
\begingroup
\catcode`φ=\active
\gdef φ{\varphi}
\endgroup
\mathcode`φ="8000
\begin{document}
\[ φ^φ \]
\end{document}
但是,如果我们换成\mathcode
使用 XeTeX 原语的版本\Umathcode
\Umathcode`φ="8 "0 "0
编译中断Bad math class (8)
,但我认为语法应该是正确的。XeTeX 文档对这个主题的描述并不详细,甚至没有提到数学类可以是 8 的情况。
那么,在 Xe(La)TeX 中定义仅在数学模式下有效的字符的正确/推荐方法是什么?使用是否\mathcode
合适,还是有些微妙的情况无法按预期工作?
答案1
A\Umathcode
需要三个数字作为参数:
- 第一个数字指定类别,范围为 0-7;
- 第二个数字指定数学家族,应该与分配的家族相对应;
- 第三个数字指定字符槽。
尤其
\Umathcode`φ="8 "0 "0
是违法的。
它类似于\mathcode
作业,其中三个部分被打包在一起放在一个十六进制数中<class><family><slot>
(两位数字<slot>
)。
32768 \mathcode
(十六进制"8000
)在标准 TeX 和 XeTeX 中都表示数学活动字符。在这方面没有任何区别。
我会以不同的方式做出定义,但这只是一个品味问题:
\begingroup\lccode`~=`φ \lowercase{\endgroup\def~}{\varphi}
\AtBeginDocument{\mathcode`φ="8000 }
这\AtBeginDocument
很重要,因为其他一些包可能会分配不同的数学代码。
答案2
在原始 TeX 中,使用 等声明数学字符\mathcode
相当于声明一个 16 位整数,其中低 8 位是字符代码。在高 8 位中,3 位用于存储 0 到 7 之间的数学类号,4 位用于记录 16 个字体系列之一,索引从 0 到 15。这样在 16 位数字中就剩下一个高位。如果设置了它(即位0x8000
),则将数学字符声明为活动字符。\mathchar
因此,a 的前四位记录了活动位和 3 位类代码。因此,谈论“类 8”并不完全正确,因为它并不存在。它只是一个 8,其中类整数通常出现在第四个十六进制数字中,因为第 16 位就是它所在的位置。
经过几年的使用,数学排版仅限 16 种字体系列(每个系列由三组单独声明的字体组成)的限制变得十分繁琐。
此外,在原始 TeX 中,单字节字符代码和字体中查找字形的索引之间没有区别。但在使用 OpenType 字体的 Unicode 世界中,存在从 Unicode 字符到字体中的字形槽号的内部映射(“cmap”表)。并且它通常不是身份映射,而在原始 TeX 中,它始终(隐式地)是身份映射。
在 XeTeX 中,\Umathchar
引入了新的基元和类似元素。它们将数学字符信息视为 32 位整数,而不是 16 位整数。这个 32 位整数被分成三个位字段,其大小分别为 8 位(用于字体系列代码 0 到 255)、3 位(用于 TeX 类代码 0 到 7)和 21 位(用于该字体系列中的“字形槽”)。
因此,新的原语需要输入三个整数(而不是一个),并且它们通常被指定为三个相邻的十六进制整数,例如"2"41"777
(类 2、系列 65、槽 1911)。然后,原语将整数组合成一个 32 位字,并进行适当的位移和参数范围验证。请注意,与经典 TeX 不同,如果将来的 TeX 解释器支持超过 8 个数学类(在 Unicode 中,已经有超过 8 个数学类,但在 XeTeX 初始化时,它们被归结为 TeX 的 8 个),则此语法不必更改。
虽然 21 位字段足以容纳任何 Unicode 代码点值,但请注意 (a) 字形槽不是 Unicode 字符,并且 (b) 21 位可以容纳非 Unicode 代码点的值。事实上,当前的 OpenType 字体最多只能容纳 65536 个字形槽。但也许未来的字体格式将支持整个 Unicode。
所以你看到了问题所在。在 32 位世界中没有额外的位可用于将扩展数学字符标记为活动数学字符。但是,Unicode 不会用尽 21 位整数中的所有可能位值,并且可能在很长一段时间内都不需要。特别是,该值0x1FFFFF
(所有 21 位都设置为 1)不是合法的 Unicode 代码点(Unicode 值在 0 到 0x10FFFF 范围内)。
因此,XeTeX 将值0x1FFFFF
(2097151) 存储在 32 位字的 21 位字形槽字段中,以表示扩展数学字符处于活动状态。这是一种黑客行为,在理想情况下不会向用户公开。但是……如果您执行以下 XeTeX 代码
{\mathcode`@="8000 \the\Umathcodenum`@}
你会发现文档布局中出现了一个神秘的十进制数 2097151,而不是你预期的 32768。但奇怪的是,它不能用作定义"1FFFFF
中的第三个整数\Umathcode
。所以
{\Umathcode`@="0"0"1FFFFF}
发出虚假的“错误字符代码”错误(虚假的原因是它不应该是一个字符,而且无论如何,它是一个字形槽,而不是一个字符)。因此,目前在 XeTeX 中,您必须使用带有常量的经典语法来声明任何活动字符"8000
。
无论如何,这就是为什么类值 8 在\Umathcode
或类似的 XeTeX 命令中不合法的原因。从技术上讲,它在旧的 TeX 世界中是不合法的,只是在将“非法”类代码 8 移到整数字中的最终位置时才起作用,在那里它设置了 16 位数学字符整数的高位。