基本上,^^^...
符号在 LuaTeX 和 XeTeX 中究竟是如何运作的?
在 8 位 TeX 引擎中(至少是最近的 TeX、eTeX、pdfTeX),两个连续相同的 catcode 7 字符(通常为^
),后跟两个小写的十六进制数字,在标记步骤之前转换为相应的字节。也就是说,^^6f
完全等同于o
:例如,\sh^^6fw ^^6f
将导致 TeX 显示the letter o
。
还有一种表示法是两个^
(相同的 catcode 7 个字符),后跟任意 ascii 字符(但不是两个小写的十六进制数字),用在字符代码中减去或加上 64 得到的字符替换,剩余的是 ASCII 字符(范围为 0 到 128)。
支持 Unicode 的引擎(我想到的是 LuaTeX 和 XeTeX,也许还有其他不太知名的引擎)也为十六进制表示为 4 或 5 位数字的字符提供 和^^^^xxxx
。^^^^^xxxxx
但这似乎在各个引擎中并不以相同的方式实现。
例如,LuaTeX 和 XeTeX 似乎都接受 4、5 或 6 个插入符号后跟相同数量的十六进制数字的表示法,但 XeTeX 也接受 3,而 LuaTeX 则不接受。使用 pdfTeX、LuaTeX 和 XeTeX 编译以下内容会产生不同的结果。
\catcode0=12
\newlinechar=10
\def\loopshow#1{\message{\meaning #1^^J}\loopshow}
\loopshow \/
^^56
^^^056
^^^^0056
^^^^^00056
^^^^^^000056
^^^^^^^0000056
{\end\iffalse}
\fi}
\bye
关于 XeTeX 的一个奇怪的事实(一个错误?)是
\show ^^^^^^010101
显示the character displaywidth
。
我的目标(可能有更好的方法)是提供一种方法来测试传递给定的标记列表是否\scantokens
安全。为此,我的计划是\detokenized
一次一个字符地检查标记列表,应用 TeX 的标记化规则(但不需要完全标记化),并检测 begin-group 和 end-group 标记以及无效字符。
答案1
首先,我想定义一些符号和函数,以便更容易地形式化答案。
符号:
x
:小写十六进制数字:0
至9
或a
至f
N
:不是小写的十六进制数字c
:字符代码小于 128 的七位字母^
:catcode 为 7 的上标字符。字符代码无关紧要,但如果连续使用,则字符必须具有相同的字符代码。
功能:
hextochar
(字符串) 返回一个字符,其字符代码由字符串参数给出字符串解释为十六进制数。charcode
(克里斯) 返回字符参数的字符代码克里斯。numtochar
(數量) 返回一个字符,其字符代码由数值参数给出數量。
针对引擎的给定转换规则将从上到下进行尝试,直到第一条规则可以应用。
TeX、eTeX、pdfTeX(“TeXbook”、“第 8 章:您输入的字符”):
^^xx
⇒hextochar
(xx
)^^c
⇒ 如果charcode
(c
) < 64 则numtochar
(c
+64 ) 否则numtochar
(c
-64 )
LuaTeX(功能process_sup_mark
在textoken.w
):
^^^^^^xxxxxx
⇒hextochar
(xxxxxx
)- 备注:
xxxxxx
不受限制,但值≥0x110100
会引起麻烦。 - 0 到
0x10ffff
:正常 Unicode 范围内的字符。 0x110000
至0x1100ff
:以字节(最后 8 位)显示的特殊字符,它们不会以 UTF-8 显示。
- 备注:
^^^^xxxx
⇒hextochar
(xxxx
)^^xx
⇒hextochar
(xx
)^^c
⇒ 如果charcode
(c
) < 64 则numtochar
(c
+64 ) 否则numtochar
(c
-64 )
XeTeX(xetex.ch
,@<如果这个 |sup_mark| 开始一个扩展字符...@>):
^^^^^^xxxxxx
⇒hextochar
(xxxxxx
)
仅当xxxxxx
≤0x10ffff
。^^^^^xxxxx
⇒hextochar
(xxxxx
)^^^^xxxx
⇒hextochar
(xxxx
)^^^xxx
⇒hextochar
(xxx
)^^xx
⇒hextochar
(xx
)^^c
⇒ 如果charcode
(c
) < 64 则numtochar
(c
+64 ) 否则numtochar
(c
-64 )
但是 XeTeX 的实现与 TeX 不兼容。例如,如果 catcode 为 7 的上标字符也是十六进制数,则 XeTeX 的行为会出乎意料:
\documentclass{minimal}
\begin{document}
\begingroup
\catcode`\4=7 % superscript
[$ 4444{a} $]
\endgroup
\end{document}
对于 TeX/e-TeX/pdfTeX 和 LuaTeX,两个上标字符44
后面跟着两个44
十六进制数字,结果为字母 D(字符代码 0x44,十进制 68),{a}
随后在数学模式下给出变量“a”。LuaTeX 看不到四个上标字符,因为它们后面没有四个十六进制数字。
XeTeX 首先看到四个上标字符。但它们后面没有四个十六进制数字。它切换到大小写^^c
,其中两个上标字符后面跟着一个非十六进制字符。结果是“t”(0x74 = 0x34('4')+ 64)。然后,第四个“4”被视为上标,它会产生以下结果{a}
。但c
实际上是“4”,一个十六进制数字。XeTeX 应该应用大小写^^xx
。因此,我认为这种行为是一个错误。
(编辑:更正下一段,65536 是正确的,而 256 是错误的——我查看了网络更改文件中错误的部分。)
的问题\show
确实是一个错误。 字符被打印出来,调用过程print
并将其字符代码作为参数。 如果此代码小于biggest_char
,则打印字符,否则将代码解释为字符串 id,并打印带有 id 的字符串(过程print
)。 的定义biggest_char
:
@d biggest_char=65536 {the largest allowed character number;
must be |<=max_quarterword|}
≤ U+FFFF 的字符显示正确,超出的字符受影响,超出的字符除外。这可用于调试字符串池 ⌣:
\catcode`\{=1
\catcode`\}=2
\catcode`\#=6
\catcode`\^=7
\catcode9=10
\def\msg#{\immediate\write16}
% #1: string index
% #2: string value
\def\StringPrintEntry#1#2{%
\msg{[#1: #2]}%
}
% #1: string index
% #2: messge
\def\StringError#1#2{%
\msg{! [#1] #2}%
}
\def\StringPrintCount#1{%
\msg{==> #1 strings available.}%
}
% #1: start index (zero based, including)
% #2: number of entries
\def\StringList#1#2{%
\begingroup
\countdef\i=11 % string index
\countdef\m=12 % limit for string index
\countdef\u=13 % char index
\chardef\1=1 %
\i=#1\relax
\m=#2\relax
\advance\m\i
\u=\i
\advance\u "10000\relax
\StringProcess
\endgroup
}
\def\StringProcess{
\ifnum\i<\m
\ifnum\u<"110000 %
\lccode`0=\u
\lowercase{%
\edef\x{%
{\the\i}%
{\expandafter\StringStripPrefix\meaning 0}%
}%
}%
\expandafter\StringProcessEntry\x
\advance\i\1
\advance\u\1
\else
\let\StringProcess\relax
\expandafter\StringError\expandafter
{\the\i}%
{Index is too large.}%
\fi
\else
\let\StringProcess\relax
\fi
\StringProcess
}
\def\StringProcessEntry#1#2{%
\def\s{#2}%
\ifx\s\StringInvalid
\ifnum\i=5 % magic
\StringPrintEntry{#1}{#2}%
\else
\let\StringProcess\relax
\StringError{#1}{End of strings reached.}%
\fi
\else
\StringPrintEntry{#1}{#2}%
\fi
}
\def\StringStripPrefix#1 #2 {}
\def\StringInvalid{???}
\def\StringCount{%
\begingroup
\countdef\c=14 %
\c=0 %
\def\StringPrintEntry##1##2{%
\advance\c\1
\xdef\StringResult{\the\c}%
}%
\def\StringError##1##2{}%
\StringList{0}{"10FFFF}
\endgroup
\StringPrintCount{\StringResult}%
}
\StringList{0}{40}
\StringCount
\csname @@end\endcsname\end
结果:
This is XeTeX, Version 3.1415926-2.4-0.9998 (MiKTeX 2.9) (INITEX)
(C:\Users\one\test\test-xetex-strings.tex
[0: .4]
[1: .9998]
[2: buffer size]
[3: pool size]
[4: number of strings]
[5: ???]
[6: m2d5c2l5x2v5i]
[7: End of file on the terminal!]
[8: ! ]
[9: (That makes 100 errors; please try again.)]
[10: ? ]
[11: Type <return> to proceed, S to scroll future error messages,]
[12: R to run without stopping, Q to run quietly,]
[13: I to insert something, ]
[14: E to edit your file,]
[15: 1 or ... or 9 to ignore the next 1 to 9 tokens of input,]
[16: H for help, X to quit.]
[17: OK, entering ]
[18: batchmode]
[19: nonstopmode]
[20: scrollmode]
[21: ...]
[22: insert>]
[23: I have just deleted some text, as you asked.]
[24: You can now delete more, or insert, or whatever.]
[25: Sorry, I don't know how to help in this situation.]
[26: Maybe you should try asking a human?]
[27: Sorry, I already gave what help I could...]
[28: An error might have occurred before I noticed any problems.]
[29: ``If all else fails, read the instructions.'']
[30: (]
[31: Emergency stop]
[32: TeX capacity exceeded, sorry []
[33: If you really absolutely need more capacity,]
[34: you can ask a wizard to enlarge me.]
[35: This can't happen (]
[36: I'm broken. Please show this to someone who can fix can fix]
[37: I can't go on meeting you like this]
[38: One of your faux pas seems to have wounded me deeply...]
[39: in fact, I'm barely conscious. Please fix it and try again.]
==> 1381 strings available.
)
No pages of output.
Transcript written on test-xetex-strings.log.