如何改变环境定义中的 catcodes?

如何改变环境定义中的 catcodes?

我尝试找到一种巧妙而可靠的方法来在%, _, ], [环境定义中使用非字母符号,例如 etc.。例如,我尝试将 [和更改]为字母以便在本地使用它们。以下代码运行良好

\begingroup
\catcode`\[=11
\catcode`\]=11
\def\[a{some unicode character}
\def\]m{something else}

\[a\]m
\endgroup

但当我尝试将上述代码放入一个特殊的环境中时

\newenvironment{newaccents}{\begingroup%
\catcode`\[=11%
\catcode`\]=11%
\def\[a{some unicode character}
\def\]m{something else}
}{%
\catcode`\[=12%
\catcode`\]=12%
 \endgroup}

TeX 抱怨

Undefined control sequence.
 \begin{newaccents}\[a
                           \end{newaccents}

所以我的问题是:如何以本地特殊方式改变非字母字符的代码,以便它们可以在本地定义的命令的定义中使用?

答案1

假设你真的想要做到这一点,你需要一个两步方法:首先在正确的类别代码设置下定义你想要的命令

\begingroup
\catcode`[=11 \catcode`]=11
\gdef\[a{foo}
\gdef\]m{baz}
\endgroup

然后您可以定义环境以便它改变类别代码:

\newenvironment{newaccents}
  {\catcode`[=11 \catcode`]=11 }
  {}

你尝试失败的原因是当你这样做

\newenvironment{newaccents}{\begingroup%
\catcode`\[=11%
\catcode`\]=11%
\def\[a{some unicode character}
\def\]m{something else}
}{%
\catcode`\[=12%
\catcode`\]=12%
 \endgroup}

TeX 已经将三个参数中的标记吸收到具有类别代码 12 的\newenvironment制度下,因此它们不能再被更改。[]

我在第一个代码块中给出的全局定义对环境之外的使用没有影响,其中和 的newaccents类别代码为 12。您仍然可以在环境中使用和及其原始含义,只要确保它们后面有一个空格即可。[]\[\]newaccents

无论如何,您应该记住,执行类别代码更改的环境不能用作命令的参数。


还有一种不同的策略可以在不改变类别代码的情况下获得类似的结果。

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\DeclareTextCommand{\NAlbrack}{T1}{?} % default is not really defined
\DeclareTextCompositeCommand{\NAlbrack}{T1}{a}{foo}
% other composites of the form \[x

\DeclareTextCommand{\NArbrack}{T1}{?} % default is not really defined
\DeclareTextCompositeCommand{\NArbrack}{T1}{m}{baz}
% other composites of the form \]x

\newenvironment{newaccents}
  {\let\[\NAlbrack \let\]\NArbrack}
  {}

\begin{document}

\[a=b\]

\begin{newaccents}
Does \[a print `foo'?

Does \]m print `baz'?
\end{newaccents}

\end{document}

在此处输入图片描述

这当然意味着\[不能\]用于显示,但我不认为这对您的应用程序来说是个问题。

我使用T1作为字体编码,但您可以使用\encodingdefault,只要代码是在加载字体编码包后,无论是fontenc还是fontspec

诀窍是定义一个\NAlbrack可以期待声明的组合的命令,在本例中是a。如果找到它,它会打印您定义的组合,否则它会打印?(只是一个任意选择,如果没有预定义的组合,您可以定义它来执行其他操作)。

在 的主体中newaccents,我只需将其更改\[为与 相同\NAlbrack

答案2

我认为在这里更改 cat 代码没有什么意义:\[a如果真的需要的话,它是一个“有效的”命令名称。

因为所有内容都是在环境中定义的,\begingroup并且\endgroup在这里根本不需要。

\documentclass{article}

\usepackage[utf8]{inputenc}


\newenvironment{newaccents}{%\begingroup%
%\catcode`\[=11%
%\catcode`\]=11%
\def\[a{some unicode character}%
\def\]m{something else}%
}{%
%\catcode`\[=12%
%\catcode`\]=12%
% \endgroup
}

\begin{document}
\begin{newaccents}
\[a äöü \]m
\end{newaccents}
\end{document}

答案3

在定义期间暂时更改 catcode;然后它们恢复为默认值,直到您的环境按照现在的方式重新激活它们。

\catcode`[=11
\catcode`]=11
\newenvironment{newaccents}{
      \catcode`[=11
      \catcode`]=11
\def\[a{(Accent)}
}{}
\catcode`[=12
\catcode`]=12

请注意,这\begin将为您开始一个组;并且由于 catcode 是本地的,因此无需手动将其设置回去。

编辑: 当然 \global\newenvironment不起作用。现已修复,抱歉打扰了。

答案4

以下答案对@egreg 的答案没有太大帮助,但展示了一种达到相同结果的替代的、稍微更紧凑的路线,可能会有所启发。

如上所述,这里需要了解的关键是 TeX 为每个字符分配一个 (catcode, charactercode) 对一次, 几时第一的读取。这意味着你的操作\def\[a必须发生在[使用 catcode 11 进行读取的上下文中。

要知道的第二件事是,环境\begin{foo} ... \end{foo}扩展为(本质上)\begingroup\foo ... \endfoo\endgroup(加上一些簿记);也就是说,您可以(大部分){foo}仅通过定义一对宏\foo和来定义一个环境\endfoo

因此:

\begingroup
\catcode`\[=11 % treat [ as a letter within this group
\gdef\newaccents{% Now define the {newaccents} environment
  \def\[a{foo}% a macro with a two-letter name
  \catcode`\[=11 % make [ a letter within the body of this environment
}
\global\let\endnewaccents=\relax
\endgroup

注意,这是\def\[a在小组内发生的,因此它被解释为两个字母。这意味着这个和‘逃离’群体\gdef的定义。\foo

在那之后...

\begin{document}
Here is text.
\[
E=mc^2.
\]

\begin{newaccents}
  Here is some \[a text, with displayed maths:
  \[ F=ma. \]
\end{newaccents}

\end{document}

这样做意味着您不必希望它能\global\newenvironment奏效。此外,此解决方案与@egreg的解决方案之间的区别(太小而没有太大优势)在于,在环境\[a之外根本没有定义,甚至无法访问{newaccent}

相关内容