根据 TeXbook* 的描述
\if<token1><token2>
构建于第 209 页(重点是我的)
TeX
将扩展后面的宏,\if
直到找到两个不可扩展的标记。如果任一标记是控制序列,则TeX
认为它具有字符代码 256 和类别代码 16,除非该控制序列的当前等价物等于\let
非活动字符标记。这样,每个 token 指定一(character code, category code)
对。
如果其中一个或两个不可扩展标记都是活动字符,该怎么办?例如
\catcode`@=13%
\if\noexpand @ ...
在构造体的“眼中”,主动角色的有效角色代码是什么\if
?
* 第 20 次印刷,Addison-Wesley 1991
答案1
如果你用抑制扩展,\noexpand
那么它就像一个命令名称,所以如果它被设置为一个字符,那么它就是一个字符代码,
如果使用 抑制扩展,\string
则会\if
看到 catcode 12 的非活动标记,其中包含原始字符的字符代码。
\catcode`@=13
\let@=X
\if\noexpand @X yes \else no\fi
\if\noexpand @ \string@ yes \else no\fi
\bye
使
是 否
因为\noexpand
这里的测试等于 X,所以它等于\let
X,但请注意,如果字符等于\let
这里的字符,那么它是不可扩展的,所以\noexpand
不需要。
答案2
请务必小心!您的代码是
\catcode`@=13%
\if\noexpand @ ...
第一行以 开头\catcode
,因此 TeX 开始进行赋值。它找到数字`@
(字母常数),因此赋值给 类别代码@
。然后=
基本上被忽略,因为它是可选的,现在 TeX 想要看到<number>
。
<number>
它找到了两个数字,但是只有当出现非数字时,对它的求值才会结束,并带有宏扩展。
如果删除%
,则行尾会生成一个空格标记,并且这是一个非数字,因此<number>
TeX 正在寻找的被确定为13
(并且空格标记将被忽略)。
对于%
,TeX 发现\if
是可扩展的,因此 TeX 会对其进行扩展。 的扩展\if
为空,但 TeX 首先会扩展标记,直到找到两个不可扩展的标记,然后对它们进行比较;比较后它将返回 true 或 false。
下一个标记是\noexpand
,它本身是可扩展的,因此它被扩展;它的扩展为空,但是下一个标记(无论它是什么)如果是可扩展的控制序列则暂时等同于\relax
,如果是活动字符则暂时等同于字符本身,这样就结束了对第一个不可扩展标记的查找。
下一个标记@
是没有尚未更改其类别代码,因为分配尚未结束。只有在找到下一个不可扩展的标记(在本例中为空格)后,TeX 才会确定它<number>
仍在寻找的确实是13
,并将继续执行分配。
检查以下代码,其中使用组来限制类别代码的变化,以免破坏以下测试。
\let\at=@
\begingroup
\catcode`@=13%
\if\noexpand @\at \message{true}\else\message{false}\fi
\endgroup
\begingroup
\catcode`@=13%
\if @\at \message{true}\else\message{false}\fi
\endgroup
\begingroup
\catcode`@=13
\if @\at \message{true}\else\message{false}\fi
\endgroup
终端上的输出是
true true
! Undefined control sequence.
l.15 \if @
\relax \message{true}\else\message{false}\fi
并且只有在第三次测试中才@
变为活跃状态,才\if
进行测试。
如果第三次测试
\catcode`@=13
\if \noexpand @\at \message{true}\else\message{false}\fi
那么它也会返回 true,因为只会返回没有扩展能力的\noexpand @
字符。@
故事的道德启示:常量后总是留一个空格。