我的目标是了解字符字节和字符标记关于换行字节。我可能没有弄清楚事实。
当 TeX 读取字节文件时,必须考虑编码。除此之外,
我们可以观察到单个换行符字节(假设 LF 和 CRLF)被转换为空格。但幕后发生了什么?是否使用数据对(LF 字节数,catcode=10)创建 token?
两个连续的换行符字节成为具有数据对(空间字节数,类别代码 5)的单个标记?
catcode 5“线路终点”何时开始发挥作用?
我知道\par
当遇到两个连续的行结尾时,LaTeX 会插入一个。
代码
我尝试直观地显示 catcode 5 的标记,但我仍然不确定它是否\tmp
真正变成了 catcode 5。
\documentclass{article}
\usepackage{fontspec}% xelatex
\long\def\scan#1{#1\par\rule{\textwidth}{2pt}\par\xscan#1\relax}
\long\def\xscan{\afterassignment\xxscan\let\tmp= }
\long\def\xxscan{%
\ifx\tmp\relax\else%
\ifcat\tmp\space10 \else%
\ifcat\tmp a11 \else%
\ifcat\tmp 112 \else%...
\ifcat\tmp
5
\else%
\fi\fi\fi\fi
\expandafter\xscan
\fi}
\begin{document}
\scan{ mac::exception ==
a
}
\end{document}
笔记
- xelatex 支持 utf-8,必须知道如何读取 2 字节的行尾。
- 代码修改自:我怎样才能让 LaTeX 识别我的宏中的空格(catcode 10)?
答案1
永远不会有任何带有 catcode 5 的令牌。
Initex 成立
\catcode`\^^M=5
但这类似于
\catcode`\%=14
这使得%
catcode 为 14,但没有具有该 catcode 的标记,如果扫描到具有 catcode 14 的字符,则会丢弃该字符和该行的其余部分。
catcode 5 的字符会生成一个空格字符,并使 tex 的扫描仪处于特殊模式,这会导致紧随其后的 catcode 10 字符被丢弃“行首的空格”,并且 catcode 5 的后续字符将被标记为非\par
空格标记“空行等同于\par
”
因此请注意,第一个换行符总是会形成一个空格,后续换行符则会形成\par
一个空行,因此通常等同于space\par
。
答案2
角色有一个类别代码;他们能在标记化阶段生成字符标记,但它们不需要到。
类别代码有两个用途:在标记化过程中(当 TeX 从输入文件或终端吸收文本时)查看它们,并且在标记列表处理期间也查看它们。
仅限具有类别代码的字符
1 2 3 4 6 7 8 10 11 12 13
可以分别生成字符标记(具有相同的类别代码)
开始组
结束组
数学 移位
对齐
参数
上标 下标 空格
字母 其他字符 活动 字符
类别代码为 0 5 9 14 15 的字符将绝不生成具有相同类别代码的字符标记:具有这些类别代码的字符标记无法通过 TeX 内部标记处理器:
类别代码为 0 的字符会触发控制序列的形成
类别代码为 9 的字符将被忽略
类别代码为 15 的字符会引发错误,然后被忽略
类别代码为 14 的字符指示标记处理器将其与行中的所有其他字符一起忽略
更有趣的是类别代码 5,也就是你问题的对象。当 TeX 找到一个时,它会丢弃输入行上剩余的所有内容,生成一个空格字符字符代码为 32、类别代码为 10,就好像它一开始就在该行上,并将扫描仪设置为忽略空格(类别代码 10)的特殊状态,直到遇到不同的情况:如果这是类别代码 5 的另一个字符,则 TeX 生成一个\par
标记,否则进入正常状态。
注意强调空格字符以上:这个空格字符按照正常规则被标记,所以如果它跟在控制字(如\foo
)后面但不在控制符号(如\~
)后面,它将被忽略。
这样做的结果是以下输入
\foo\baz
\foo \baz
\foo \baz
完全等价。请注意,如果最后一个输入中的行尾生成了太空代币,就会有区别。但事实上空格字符而是生成 (尚未标记化)。
笔记。上面关于忽略字符的说法在面对控制字形成时可能会产生误导。控制字的形成以类别代码 0 字符开始,后跟类别代码 11 字符。任何类别代码不同于 11 的字符都将停止扫描,导致形成的控制字被标记化并被重新检查(例如,如果其类别代码为 9,则被忽略)。
关于 XeTeX 和 LuaTeX 的附录。当 UTF-8 编码文件被输入到 Unicode 感知引擎时,字符在其 UTF-8 表示中是单字节、双字节、三字节还是四字节长度都无关紧要。这两个引擎执行了将 UTF-8 组合转换为 Unicode 实体的初步步骤,因此标记化处理器看到的只是一个字符(其类别代码在初始化表中分配)。这两个引擎还能够处理 UTF-16 或 UTF-32、小端或大端。
答案3
TeX 确实逐行读取输入:将读取并处理一行输入。然后读取并处理另一行输入。...
TeX 在读取一行输入后所做的第一件事就是将字符从计算机平台的字符编码方案转换为 TeX 引擎的内部字符编码方案。对于传统的 TeX 引擎,内部字符编码方案是 ASCII,即美国信息交换标准代码。对于基于 LuaTeX 或 XeTeX 的 TeX 引擎,内部字符编码方案是 Unicode,其中 ASCII 是其严格子集。
之后 TeX 会删除行右端的所有空格字符。更准确地说:之后 TeX 会删除行右端所有字符代码为 32 的字符。(32 是空格字符在 ASCII 和 Unicode 中的代码点编号。)
然后 TeX 在行的右端插入一个字符,其字符代码等于整数参数的值\endlinechar
通常
的值为\endlinechar
13,第13个字符(回车符)的类别码为5(行尾)。
这意味着 TeX 在对行进行标记并到达行尾时,通常会遇到类别代码为 5(行尾)的字符。
然后 TeX 开始对这一行进行标记。也就是说,TeX “查看”这一行包含的字符,并根据类别代码表和读取设备的状态生成控制序列标记和字符标记。
在读取和标记输入时,TeX 的读取装置可以处于以下三种状态之一:
状态:跳过空白。阅读器将处于状态 S
- 处理输入中类别代码为 10(空格)的字符后。
- 处理类别代码为 7(上标)的两个相同字符序列,然后处理类别代码为 10(空格)的字符的小写十六进制表示的两个字符序列。
[示例:的类别代码通常^
为 7(上标),而字符 32(空格字符;十六进制 20)的类别代码通常为 10(空格)。因此,通常将该表示法^^20
视为处理类别代码通常为 10(空格)的输入中的字符 32(空格字符)。] - 处理类别代码为 7(上标)的两个相同字符序列后,接着处理一个字符,如果该字符的字符代码在 64 到 127 的范围内,则减去 64 得到的字符的类别代码为 10(空格)。
[示例:由于的类别代码^
通常为 7(上标),的字符代码`
为 96,而 96-64=32,字符 32(空格字符)的类别代码通常为 10(空格),因此通常将该符号^^`
视为从类别代码通常为 10(空格)的输入中处理字符 32(空格字符)。] - 处理类别代码为 7(上标)的两个相同字符序列后跟一个字符,其中 - 如果字符的字符代码在 0 至 63 范围内 - 则通过添加 64 获得的字符的类别代码为 10(空格)。
- 产生一个控制字标记之后。
- 生成一个控制符号标记后,该标记的名称由类别代码 10(空格)的字符组成。例如,生成控制符号标记
\␣
(控制空格)后。
在状态 S 中,处理类别代码为 10(空格)的字符和处理被认为等同于类别代码 10(空格)的字符的^^..
-sequence/ <superscript-char><superscript-char>..
-sequence 都将不会产生任何标记,也不会改变读取设备的状态。
通常,空格字符(字符代码 32)和水平制表符(字符代码 9)是仅有的类别代码为 10(空格)的字符。
这就是为什么你可以在输入中有几个连续的空格字符或水平制表符,通常只产生一个空格标记,反过来,在 TeX 处于空格标记产生水平粘连的模式之一的情况下,只产生一个水平空格的水平粘连(即,在水平模式下,在受限水平模式下,但在垂直模式下,在内部垂直模式下,在数学模式下,在显示数学模式下)。
州 M:行中间。读取装置将处于状态 M
- 产生非空格字符标记后。
- 生成一个控制符号标记之后,该标记的名称由非类别代码 10(空格)的字符组成。
在状态M下,处理类别代码为10(空格)的字符和处理被认为等同于类别代码10(空格)的字符的^^..
-序列/ <superscript-char><superscript-char>..
-序列都将产生空格标记,即charcode为32(空格字符)且catcode为10(空格)的字符标记,并将读取装置的状态切换到状态S。
州 N:新行。读取装置在即将开始读取另一行输入时处于状态 N。在状态 N 中,处理类别代码为 10(空格)的字符和处理被认为等同于类别代码为 10(空格)的字符的^^..
-sequence/ <superscript-char><superscript-char>..
-sequence 都将导致不产生任何标记,也不会改变读取装置的状态。
如果 TeX 在读取设备处于状态 S 时遇到类别代码 5(行尾)的字符,则 TeX 根本不会生成任何标记。
如果在读取设备处于状态 M 时,TeX 遇到类别代码为 5(行尾)的字符,则 TeX 将产生一个空格标记,即 characode 为 32(空格字符)且 catcode 为 10(空格)的字符标记。
如果 TeX 在读取设备处于状态 N 时遇到类别代码 5(行尾)的字符,TeX 将产生控制字标记\par
。
遇到类别代码 5(行尾)的字符后,TeX 将- 无论读取装置处于何种状态 -无论如何,删除当前行上的任何进一步信息并开始读取另一行输入。这样 TeX 的读取装置将切换到状态 N。
由于上述原因,\endlinechar
通常非空行后的空行会导致 TeX 处理两个连续的返回字符(字符代码 13),其类别代码为 5(行尾)。
在遇到第一个返回字符时(该字符在非空行中),读取装置可能处于状态 S 或状态 M,因此第一个返回字符可能根本不产生任何标记或产生一个空格标记。
无论如何,在遇到第一个返回字符后,读取装置将切换到状态 N。因此当遇到第二个这样的返回字符时,读取装置处于状态N,并且第二个这样的返回字符将产生控制字标记 \par
。
这就是为什么通常将空行视为“段落分隔符”/像控制字标记一样对待,\par
其通常(如果没有重新定义)是用于将现在收集/聚集的材料分成几行并将它排版为一段文本的指令。
这意味着段落中的最后一个元素是空格标记,这会产生水平粘连。请注意,段落末尾的这种水平粘连通常会被 TeX 丢弃,并且根据 -glue \parfillskip
-parameter 的值将粘连附加到段落末尾。