\lowercase 技巧与 \gdef

\lowercase 技巧与 \gdef

在这个 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不是。它设置起来更困难,与其他包交互时可能会出现问题,并且不允许您以编程方式更改字符。

相关内容