在这个 MWE 中,我定义了一个环境,其中一个特定的字母被激活,并且具有某种含义,一次使用技巧\lowercase
,一次使用\gdef
:
\documentclass{article}
\begingroup
\catcode`\A=\active
\gdefA#1{(#1)}
\endgroup
\newenvironment{foo}{\catcode`\A=\active }{}
\begingroup
\lccode`\~=`\B
\lowercase{\endgroup\def~}#1{(#1)}
\newenvironment{baz}{\catcode`\B=\active }{}
\begin{document}
\begin{foo}foo Abaz A{bar}\end{foo}
\begin{baz}foo Bbaz B{bar}\end{baz}
\end{document}
两种环境当然都会产生相同的输出:
我想知道是否有理由选择一种方法而不是另一种方法。
答案1
首先,这个\lowercase
技巧不需要分配是全局的,所以无论你改变什么定义,它都将被限制在当前范围内,这通常是你想要的(如果不是,你也可以在代码\gdef
中使用\lowercase
)。
但可能主要的优点是,这个\lowercase
技巧允许你即时“生成”活动字符,而使用\gdef
方法时必须直接输入活动字符(实际上,在\lowercase
方法中,活动字符是直接输入,但它是~
,已经处于活动状态)。
假设您的环境接受一个参数,即要激活的字符。使用简单的\gdef
方法,这是不可能的:
\documentclass{article}
\newenvironment{baz}[1]{%
\begingroup
\lccode`\~=`#1
\lowercase{%
\endgroup\def~}##1{(##1)}%
\catcode`#1=\active
}{}
\begin{document}
\begin{baz}{B}foo Bbaz B{bar}\end{baz}
{\catcode`\B=\active \show B}
\end{document}
并\show B
表明“active-char-B”的定义在全局上没有改变:
> B=undefined.
l.16 {\catcode`\B=\active \show B
}
?
您可以使用另一个技巧来避免\gdef
第一种方法中的 。如果这样做,则假设\@firstofone
具有其通常的 LaTeX 含义 ( \@firstofone=\long macro:#1->#1
):
\makeatletter
\begingroup
\catcode`\A=\active
\@firstofone{%
\endgroup
\defA}#1{(#1)}
\@firstofone
然后,的参数将在处理\endgroup\defA
之前被标记化,因此即使在 之后仍将是,因此更改将仅限于当前范围。但是,如果您想用它创建一个环境,您仍然无法自动生成活动角色,因此您需要逐个“激活”每个角色(并确保它们在您定义环境时处于活动状态)。\endgroup
\defA
\def
<active-char-A>
\endgroup
下面是一个示例,说明该\lowercase
方法如何更好地在局部更改字符的含义,同时在宏/环境范围之外保留其含义。在这个例子中,我利用了法语babel
构成!
活动字符的事实。考虑使用这个技巧的这个例子\lowercase
:
\documentclass{article}
\usepackage[french]{babel}
\newenvironment{baz}[1]{%
\begingroup
\lccode`\~=`#1
\lowercase{%
\endgroup\def~}##1{(##1)}%
\catcode`#1=\active
}{}
\begin{document}
\show! % > !=macro:->\active@prefix !\active@char!
\begin{baz}{!}foo !baz !{bar}\end{baz}
\show! % > !=macro:->\active@prefix !\active@char!
\end{document}
这个使用直接输入!
:
\documentclass{article}
\usepackage[french]{babel}
\newenvironment{baz}[1]{\catcode`!=\active}{}
\begin{document}
\show! % > !=macro:->\active@prefix !\active@char!
\makeatletter
\begingroup
\catcode`\!=\active
\@firstofone{%
\endgroup
\def!}#1{(#1)}
\makeatother
\begin{baz}{!}foo !baz !{bar}\end{baz}
\show! % > !=macro:#1->(#1)
\end{document}
它们的代码基本相同。它们的主要区别在于:
1) 在\lowercase
版本中,定义可以放在前言中,因为它动态地(滥用单词的含义)生成活动!
字符,而无需先设置它。在\gdef
版本中(我没有使用\gdef
,但只是为了保留您问题中的命名),要使用的字符的设置!
需要在 之后\begin{document}
,否则您的定义将被 覆盖babel
。
2) 您失去了babel
的定义,!
因为您必须全局定义 的含义active character !
(或任何恰好具有有效含义且您在环境中使用的代码)。版本\lowercase
允许您将此定义保留在本地,因此您无需担心这一点。
总体而言,没有理由更喜欢“\gdef
方法”而\lowercase
不是。它设置起来更困难,与其他包交互时可能会出现问题,并且不允许您以编程方式更改字符。