该命令\catcode
通常用于更改一些内部内容。例如,该命令\makeatletter
更改 catcode @
。但它是什么\mathcode
,它是如何工作的?
catcodes 在此处有很好的解释:Wiki TeX 目录代码
与之相关的\mathcode
命令可以找到\delcode
。请添加一些关于这些命令的一致性的信息。
答案1
在文本中,字符标记只有两个属性,即字符代码和类别代码。如果+
在文件中看到,则(通常)给出类别代码 12(标点符号),字符代码来自文件编码,因此在本例中为 43。
在数学模式列表中,数学原子需要更多的结构,每个符号来自不同的字体,并根据其类别(运算符、二进制中缀、关系等)获得不同的间距。在典型的 1970 年代风格中,这些属性被紧凑地打包成单个整数中的位字段,称为数学码,通常以十六进制表示,因此您可以轻松地将这些字段分开。+
纯文本中的数学码设置为
\mathcode`\+="202B
这意味着它属于类 2(二进制中缀)、fam0(罗马字体)和字符十六进制 2B,即十进制 43(罗马字体编码中 + 的字符代码)。
正如 egreg 在评论中指出的那样,数学代码仅用于普通字符标记,即 catcode 11 和 12(字母和标点符号),具有特殊 catcode(如 4)的字符标记(通常)保留其特殊行为,并且不参考其数学代码。但是,如果您从宏或 via&
生成 catcode 12,则将参考其数学代码。&
\string&
\delcode
类似,但包含一些额外的位,因为分隔符需要更多信息,(
纯文本的解码是
\delcode`\(="028300
这表明小字符(
来自字体 \fam0 中的十六进制 28 位置,但随后您需要切换到字符十六进制 0\fam3
才能获得大括号。(字体指标指定了用于构建更大字符的字形链(如果需要),但它们需要知道从哪里开始。
\mathcode"8000
是一种不以常规方式查找的特殊代码。如果字符具有该数学代码,则将使用活动(catcode 13)标记的定义,即使字符本身不是活动的。这在纯文本和 LaTeX 中用于允许'
在文本中用作正常的非活动撇号,但在数学中它具有 catcode 十六进制 8000,因此使用活动定义,扩展为^{\prime}
。
答案2
我想补充一个最近对我来说至关重要的技术要点:虽然\catcode
更改是出了名的脆弱,因为它们不能在标记化之后发生(具体来说,在读取宏的参数之后),但\mathcode
更改能发生。例如,我有以下宏:
\def\genby#1{\langle#1\rangle}
在代数中指定某个事物的生成器,其中#1
表示生成集。如果我有几组生成器,我当然想使用数学上正确的符号,\genby{S \cup T}
而不是更简单但不太正确的符号\genby{S, T}
。不幸的是,我总是忘记,所以我没有搜索并替换所有逗号,而是尝试重新定义命令:
{\catcode`\,=\active \gdef,{\cup}}
\def\genby#{%
\langle\bgroup \aftergroup\rangle
\catcode`\,=\active
\let\next=
}
(使用这个技巧以避免标记化),虽然这在$\genby{S,T}$
(产生相当于)中可以正常工作,但在构造$\genby{S \cup T}$
中却完全失败了amsmath
\begin{gather}
\genby{S,T}
\end{gather}
但它没有效果!我立即意识到这是一个“amsmath
读两次参数”的例子(我第一次了解到这个问题(这不是它在这个网站上出现的唯一地方),并认为这是一个标记化问题,阻止了 catcode 更改。所以我尝试了\mathcode
(另请参阅 egreg 的评论):
{\catcode`\,=\active \gdef,{\cup}}
\def\genby#1{%
\langle\begingroup
\mathcode`\,="8000
#1
\endgroup\rangle
}
或者,如果不使用活动逗号的全局定义,这可能会与其他包发生冲突,
\newcommand{\genby}[1]{%
\begingroup
\begingroup\lccode`\~=`\,
\lowercase{\endgroup\let~\cup}%
\mathcode`\,=\string"8000
\langle#1\rangle
\endgroup}
并且这再次起作用,即使在gather
。
此功能强调了数学模式的一个重要理论点:在数学模式下操作时,TeX 具有中间的解释阶段,类似于标记化,在此阶段,它会构建一个“数学列表”,该列表不仅仅是文本输入(“代码”),而且少于排版输出(“水平列表”)。数学代码、delcode 等的解释仅在从标记化输入流转换为数学列表时发生,因此会更改其中一个是标记化后有效。(但是,一旦构建了数学列表,您仍然无法执行任何操作。)