保存并恢复 makeatletter/makeatother 状态

保存并恢复 makeatletter/makeatother 状态

在发布定义或修改包含 @ 的命令的 Latex 代码片段时,通常会包含\makeatletter...\makeatother包装器,如果将代码片段粘贴到普通文档中,则需要此包装器。但是,如果这种粘贴恰好发生在\makeatletter已经生效的地方,则会产生不良影响。有没有一种好方法可以“保存‘at’的状态”,执行一些代码,然后恢复原始状态(无论它是什么状态)?

(是的,我知道\makeatletter/\makeatother对组来说是本地的。但是,某些代码在组内的工作方式不同,例如,宏定义默认对组来说是本地的,因此最好避免将整个代码片段放在组中。)

答案1

在某些情况下,我会这样做:

\begingroup
\makeatletter
\@firstofone{%
  \endgroup
  ⟨Stuff/macro-definitions whose tokenizing needs to
   take place while `@` is of category-code 11(letter)
   but whose processing/carrying-out/running/execution
   is to take place while the category-code of `@` is
   what it was before encountering \makeatletter.⟩
}%

的参数\@firstofone将在局部范围内读取和标记,其中 的@类别代码为 11(字母),因此@可以是控制字标记名称的一部分,也可以被标记化为类别代码为 11(字母)的显式字符标记。
在处理/执行/运行/执行由于读取和标记 的参数而产生的那些标记时\@firstofone,第一个\endgroup将终止该局部范围,将 的类别代码重置@为调用 之前的类别代码\makeatletter
因此,处理/执行/运行/执行 的\@firstofone参数的剩余标记不会在 的类别代码发生更改的局部范围内进行@,而是使用处理 -token 之前有效的类别代码机制\makeatletter

答案2

您可以定义一个新的宏来存储当前的 catcode,@并稍后使用该宏恢复它:

\documentclass{article}

\def\safemakeatletter#1{%
    \edef#1{\catcode`@=\the\catcode`@\relax}%
    \makeatletter
}

\def\testat{catcode of \texttt{@} is: \the\catcode`@\relax\par}

\begin{document}

\catcode`@=10\relax
\testat
\makeatletter
\testat
\makeatother
\testat

\medskip

\catcode`@=10\relax
\testat
\safemakeatletter\safemakeatother
\testat
\safemakeatother
\testat

\end{document}

正如您在输出中看到的,\makeatother错误地恢复了第一部分的 catcode,但\safemakeatother没有:

在此处输入图片描述

相关内容