\scantokens 与 \def 或 \gdef 等无法很好地配合

\scantokens 与 \def 或 \gdef 等无法很好地配合

我在更改 catcode 的环境中工作,需要重新扫描标记才能继续处理文本。但是,我遇到了问题。即使使用这个最低限度的代码,我仍然遇到问题。

\documentclass{article}

\makeatletter
\newcommand\aeinput[1]{%%
  \begingroup
    \scantokens{\gdef\ae@input{::#1::}}%%
  \endgroup
  \ae@input
  }%%
\makeatother

\begin{document}
\aeinput{HELLO}
\end{document}

导致错误:

! Undefined control sequence.
\aeinput ...ae@input {::#1::}}\endgroup \ae@input 

如果我写:我会得到同样的错误:

\scantokens{\xdef\ae@input{::#1::}}%%

为什么这不能编译?

另外,如果我做类似的事情

\expandafter\gdef\expandafter\ae@input\expandafter{\scantokens{::#1::}}%%

我收到以下错误:

! File ended while scanning definition of \ae@input.

即使添加也\everyoef{\noexpand}无济于事。

然而,以下确实有效(这让我更加困惑)。

\xdef\ae@input{\scantokens{::#1::}}%%

那么,这里发生了什么事?

这个问题从何而来?

我以为我有一个简单的答案在已经更改 catcode 的环境中输入文本. 基本上,在这个问题中我有一个环境

\begin{speech}
   inside here periods have a different catcode

 \end{speech}

这个问题的原作者想做类似的事情

\begin{speech}
  \input{text.tex}
\end{speech}

显然,\input在这里不起作用,因为.catcode 错误。我以为我可以\input{text.tex}通过执行以下操作轻松解决这个问题(并允许 OP 继续写入),例如

\makeatletter
\newcommand\aeinput[1]{%%
  \begingroup
  \catcode`\.=\periodcatcode
  \scantokens{\gdef\ae@input{\input{#1}}}%%
  \endgroup
  \ae@input
  }%%
\makeatother

另一种方法是

\makeatletter
\newcommand\aeinput[1]{%%
  \begingroup
  \catcode`\.=\periodcatcode
  \scantokens{\gdef\ae@filehandle{#1}}%%
  \endgroup
  \input{\ae@filehandle}%%
  }%%
\makeatother

这样,输入文件将根据speech环境适当地处理周期。

就像是

\newcommand\aeinput[1]{%%
  \begingroup
  \catcode`\.=\periodcatcode
  \scantokens{\input{#1}}%%
  \endgroup
}

仅从表面上看它可以工作,但输入文件将不再具有句点的正确 catcode。

答案1

请记住,\scantokens类别代码有效当它被使用时.因此在

\documentclass{article}

\makeatletter
\newcommand\aeinput[1]{%%
  \begingroup
    \scantokens{\gdef\ae@input{::#1::}}%%
  \endgroup
  \ae@input
  }%%
\makeatother

\begin{document}
\aeinput{HELLO}
\end{document}

\scantokens文档中插入了一行,其中不是@字母。因此 \gdef\ae@input将其定义\ae为宏,后面跟着@input替换文本::<#1>::。您需要更改组内的类别代码

\documentclass{article}

\makeatletter
\newcommand\aeinput[1]{%%
  \begingroup
    \makeatletter
    \scantokens{\gdef\ae@input{::#1::}}%%
  \endgroup
  \ae@input
  }%%
\makeatother

\begin{document}
\aeinput{HELLO}
\end{document}

正如您所观察到的,虽然\scantokens是可扩展的,但要做到这一点有点棘手,因为它使用的虚拟文件的“文件结尾”有些奇怪。这些可以解决(参见代码\tl_rescan:nn和 中的类似代码expl3),但这并不简单。

相关内容