哈拉尔·汉切-奥尔森发布了一些有趣的代码来回答这个问题。
有人可以解释一下它是如何工作的吗?
我理解(我认为)未来和扩展。我不明白:
<null>
中的人物来自哪里\ifcat\next9
?- 扩展的文本实际上是如何分解成
\hbox
's 的?(TeXbook 的第 98-99 页并没有真正帮助我理解这种情况下跟踪输出,所以我希望有人可以澄清。)
谢谢!
以下是从参考答案中复制的代码:
\def\breaknumberanywhere{\hskip0pt\futurelet\next\breaknumberi}
\def\breaknumberi{\ifcat\next9\expandafter\breaknumberii\fi}
\def\breaknumberii#1{#1\breaknumberanywhere}
\def\foo#1#2{\vtop{\hsize=#1\rightskip=0pt plus 1fil \leftskip=0pt\noindent\breaknumberanywhere#2}}
Here is a long number:
\foo{2in}
{17823941237490812347123904712389407123408917234890123748912034712985712389012351}
\bye
答案1
对你的问题 2 的简短回答:178239…
变成
\hskip0pt 1\hskip0pt 7\hskip0pt 8\hskip0pt 2\hskip0pt 3\hskip0pt 9\hskip0pt …
然后使用 TeX 的内置段落分行算法将其分行。这就是我将其设置\rightskip
为可拉伸的原因;否则我会得到过满的\hbox
es,除非我非常小心地将其设置\hsize
为数字宽度的精确倍数(大多数字体似乎都让所有数字都具有相同的宽度,这在数字表中非常方便)。
关于第一个问题,我至少可以解释一下\ifcat\next9
检查类别代码(简称 catcode)是否相等。数字以右括号结尾,其 catcode 与数字不同,因此我只需将已出现的标记的 catcode 与随机\next
选择\futurelet
的数字的 catcode 进行比较,以查看它是否\next
真的是数字。
\breaknumberanywhere
通过将下一个标记分配给\next
而不将其从输入流中删除,然后插入到\breaknumberi
输入流的前面来工作。因此,该宏在运行时,具有可用于\next
测试目的的下一个标记,并且如果它是数字,则插入\breaknumberii
到输入流的前面。\expandafter
诀窍是摆脱\fi
标记(同时终止)\if
,因此\breaknumerii
将看到下一个数字作为第一个可用标记(它将变为#1)。然后它重新启动\breaknumberanywhere
以处理下一个数字。
今天的布道到此结束。
答案2
我在注意到 Harald 的答案之前就想到了这一点,他的答案可能更好,但这是我的尝试。假设 TeX 文件有
\breaknumberanywhere 178239
在里面。
\breaknumberanywhere
被替换为\hskip0pt\futurelet\next\breaknumberi
。因此该行变为\hskip0pt\futurelet\next\breaknumberi 178239
\futurelet\a\b\c
相当于\let\a\c\b\c
,所以你会得到类似\hskip0pt\let\next1\breaknumberi 178239
现在
\breaknumberi
被扩大了,导致\hskip0pt\let\next1\ifcat\next9\expandafter\breaknumberii\fi 178239
现在
\ifcat
比较接下来两个标记的类别代码,即\next
(即1
)和9
。 (它确实不是检查的类别代码是否\next
为 9,即被忽略的或<null>
字符,根据第一个问题,您可能会想到这一点)。它们确实具有相同的类别代码,因此真正的文本被扩展,但实际上它被延迟了,因为\expandafter
允许条件结束。结果是\hskip0pt\breaknumberii 178239
\breaknumberii
将下一个标记 (1
) 作为参数并替换它,结果为\hskip0pt1\breaknumberanywhere78239
现在我们回到步骤1!
结果插入长数字的每两位数字之间,这样 TeX 就可以在任意位置换行。后面的\hskip0pt
标记不会具有与数字相同的类别代码,因此只会产生本身,而不是<tok>
9
\breaknumberi <tok>
<tok>
\breaknumberii <tok>