在发布定义或修改包含 @ 的命令的 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
没有: