这个答案如何起作用?

这个答案如何起作用?

哈拉尔·汉切-奥尔森发布了一些有趣的代码来回答这个问题

有人可以解释一下它是如何工作的吗?

我理解(我认为)未来和扩展。我不明白:

  1. <null>中的人物来自哪里\ifcat\next9
  2. 扩展的文本实际上是如何分解成\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为可拉伸的原因;否则我会得到过满的\hboxes,除非我非常小心地将其设置\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

在里面。

  1. \breaknumberanywhere被替换为\hskip0pt\futurelet\next\breaknumberi。因此该行变为

    \hskip0pt\futurelet\next\breaknumberi 178239
    
  2. \futurelet\a\b\c相当于\let\a\c\b\c,所以你会得到类似

    \hskip0pt\let\next1\breaknumberi 178239
    
  3. 现在\breaknumberi被扩大了,导致

    \hskip0pt\let\next1\ifcat\next9\expandafter\breaknumberii\fi 178239
    
  4. 现在\ifcat比较接下来两个标记的类别代码,即\next(即1)和9。 (它确实不是检查的类别代码是否\next为 9,即被忽略的或<null>字符,根据第一个问题,您可能会想到这一点)。它们确实具有相同的类别代码,因此真正的文本被扩展,但实际上它被延迟了,因为\expandafter允许条件结束。结果是

    \hskip0pt\breaknumberii 178239
    
  5. \breaknumberii将下一个标记 ( 1) 作为参数并替换它,结果为

    \hskip0pt1\breaknumberanywhere78239
    
  6. 现在我们回到步骤1!

结果插入长数字的每两位数字之间,这样 TeX 就可以在任意位置换行。后面的\hskip0pt标记不会具有与数字相同的类别代码,因此只会产生本身,而不是<tok>9\breaknumberi <tok><tok>\breaknumberii <tok>

相关内容