使用 \typeout 显示扩展的 \let 命令

使用 \typeout 显示扩展的 \let 命令

我已经看过相关页面宏 - \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被扩展了。

相关内容