我在另一个问题中发现了以下代码:
\def\scan#1{\scanA#1*}
\def\scanA{\futurelet\next\scanB}
\def\scanB{\expandafter\ifx\next\space \expandafter\scanC \else \expandafter\scanE \fi}
\def\scanC{\afterassignment\scanD \let\next= }
\def\scanD{\scanE{ }}
\def\scanE#1{\ifx*#1\else \dosomething{#1} \expandafter\scanA \fi}
其效果是将像 这样的字符串转换ABC
为\dosomething{A}\dosomething{B}\dosomething{C}
。
若\let\dosomething=\uppercase
,则\scan{Hello World!}
得HELLO WORLD!
。
我理解当\ifx\next\space
in \scanB
gets时false
它会扩展为\scanE
,它将下一个未读标记捕获为它的参数并\dosomething
。
但是,当得到 时true
,它会扩展为\scanC
。\scanD
扩展为\scanE{ }
,以便我们可以处理空格。但是为什么下一个\scanA
会跳过空格,以及和如何\afterassignment
工作\let\next=
?
===== OrthoPole 更新 =====
我想我自己已经了解了这个过程。
当\ifx
获取时true
,流看起来像\futurelet·\next·\scanB·_·...
(_
代表空格标记),并且它扩展为\afterassignment·\scanD·\let·\next·=·_·_·...
。我们看到\let
允许可选的空格标记,因此后面的第一个空格=
将被省略,并将\next
被分配第二个空格。在此分配之后,\scanD
将被扩展。由于 后面的两个空格=
被 吸收\let
,我们得到\scanD·...
。
答案1
\afterassignment\cs
将\cs
在执行下一个分配后立即重新插入到输入流中。
什么被视为赋值?设置寄存器的值(但对于盒子寄存器来说,情况略微复杂);执行\.def
代表.
无,g
,x
等等char
;执行\let
。
你的情况是最后一个。现在的语法\let
是
\let <cs><optional spaces><optional =><one optional space>
在你的情况下,这<optional spaces>
部分并不有趣,因为你总是有\let\scanD
。更有趣的是<one optional space>
。在这种情况下,TeX 会不代币跟随的扩展=
,正如所见证的
\let\x=\space\message{abc}
abc
在控制台上打印并\x
使其与相同\space
。
正在做
\def\scanC{\afterassignment\scanD \let\next}
如果后面的标记\scanC
是=
,则会失败,因为它将被视为\let
指令的一部分,这是不想要的。但也有
\def\scanC{\afterassignment\scanD \let\next=}
如果后面的标记\scanC
是显式的空格标记,则会失败,因为它将被视为<one optional space>
。
您希望分配给\next
下一个标记,因此您需要
\def\scanC{\afterassignment\scanD \let\next= }