我已经看过相关页面宏 - \let 和 \edef 之间有什么区别?但恐怕它仍然没有向我解释以下 MWE:
\documentclass{minimal}
\begin{document}
\let\tmpa=Hello
\edef\tmpb{A\tmpa}
\tmpb % typesets "ello AH"
\typeout{\tmpa} % writes "\tmpa" in terminal
\typeout{\tmpb} % writes "A\tmpa" in terminal
\end{document}
我的理解是这样的:
\let\tmpa=
看到 的第一个字符Hello
-H
它将其视为单个标记并分配给它(即\let\tmpa=H
)- “fall through”中剩余的字符(“ello”)被排版(
\let\tmpa=Hello
“ello AH” 中的“ello”) \edef\tmpb{A\tmpa}
运行 => 因为\tmpa=H
,那么\tmpb
应该扩展为“AH”\tmpb
运行 => 正如预期,“AH”在前一个“ello”之后输入
而混乱来自 \typeout{\tmpa} - 从排版输出来看,我很确定\tmpa=H
;所以我期望\typeout{\tmpa}
结果是H
,但它没有- 相反,它又会再次写入\tmpa
!如果我尝试通过扩展它\edef
并将其放入另一个命令(\tmpb
),然后尝试\typeout
该命令,则会发生同样的事情。
为什么\typeout
在这种情况下不显示 的“扩展”值\tmpa
?我怎样才能\typeout
显示 的扩展值\tmpa
?
啊,好吧,我问了这个问题;然后我要求自己把它关闭,因为显示扩展\let
命令\typeout
通常会提供答案;与此同时,我想到了一个我想记录的答案 - 但现在我不能再记录了,因为它已经关闭了,:/
所以我把答案发布在宏 - 如何将控制序列“扩展”\let
为字符?;但这个答案根本不属于那里。
然后我终于意识到我可以编辑我的问题帖子,即使它已关闭(我只是无法添加答案) - 所以最好从其他问题中删除答案,然后将其移动到这里(虽然现在它在这里,但最好它是一个答案:/
啊没关系)。
因此,为了不让管理员再次打开并关闭,我将在这里发布答案:
基本上,\typeout
该示例的内容如下:
- 用来
\meaning
转换\tmpa
为“字母 H” - 使用“解析器”宏,从一组三个单词中提取第三个单词
因此,我们最终得到了修正后的 MWE,它可以将内容\tmpa
(这里我们明确期望它是一个字母)打印到终端:
\documentclass{minimal}
\begin{document}
\def\wordIIIofIII #1 #2 #3{#3}
\let\tmpa=Hello
\edef\tmpb{A\tmpa}
\tmpb % typesets "ello AH"
\typeout{\tmpa} % writes "\tmpa" in terminal
\typeout{\tmpb} % writes "A\tmpa" in terminal
\edef\tmpc{\meaning\tmpa}
\typeout{\tmpc} % writes "the letter H" in terminal
\edef\tmpd{\expandafter\wordIIIofIII\tmpc}
\typeout{\tmpd} % writes "H" in terminal
\typeout{\the\catcode`H} % 11
% \typeout{\the\catcode`\tmpd} % "! Improper alphabetic constant."
\typeout{\the\catcode\expandafter`\tmpd} %11
\end{document}
答案1
原语的语法\let
是
\let<cs>=<token>
其中<cs>
是控制序列或活动字符,<token>
是单身的标记,=
可以省略或用可选空格括起来。因此
\let\?=H
\let\? =H
\let\? = H
\let\?H
\let\? H
都是等效的(我使用它们\?
以便在标记化阶段不会忽略任何空格)。
如此定义的<cs>
继承了 的所有特征<token>
(但根据 token 的不同,它可能总是被用作替代品,也可能不总是被用作替代品)。特别是,在
\let\tmpa=H
令牌\tmpa
将无法扩展,只是因为H
它无法扩展。
该命令\typeout
使用\write
确实扩展的机制,但使用从未分配文件的输出流,因此结果写入终端和日志文件,同时添加指令以便\protect
其正确工作(例如\typeout{\itshape}
打印\itshape
,而\write255{\itshape}
会爆炸)。
在 下\write
,不可扩展标记按其名称书写。这样写是好的:在 之后\write\@outputstream{\bgroup}
,在输出中发现{
可能是灾难性的。同样,人们也有充分的理由写出\tmpa
而不是H
。
的策略\meaning
是正确的,但它只在这种特殊情况下有效,而使用 则会失败\bgroup
,其含义是
\bgroup=begin-group character {
您可能会发现查看该expl3
函数很有用\tl_analysis_show:N
;编译以下文件
\RequirePackage{expl3}
\let\tmpa=H
\ExplSyntaxOn
\tl_analysis_show:n { \tmpa }
将显示在终端上
The token list contains the tokens:
> \tmpa (control sequence=the letter H).
(对于 TeX Live 2017 之前的版本,\usepackage{l3tl-analysis}
除了 之外,您还需要 才能\usepackage{expl3}
使用此功能\tl_show_analysis:N
,现在这是一个已弃用的命令。)
为什么不起作用\typeout{\the\catcode`\tmpd}
?因为字母常量是`<character>
(其中<character>
也可能是<backslash><character>
),并且在反引号后发现多字母控制序列,这是非法的。
这行代码\typeout{\the\catcode\expandafter`\tmpd}
有效,因为\catcode
会扩展标记,直到找到可以启动 a 的东西<number>
(如果找不到,TeX 会报错)。所以 a\expandafter
被扩展了。