理解修改类别代码的示例

理解修改类别代码的示例

有一个问题是关于在句号和逗号后自动添加空格。对此的回答包括修改类别代码。如下所示。

\documentclass{article}
\usepackage{expl3}

\makeatletter
\catcode`.13
\def.{\char`.\@ifnextchar'{}{\@ifnextchar.{}{ }}}
\makeatother
\def\Abbr{\catcode`.12}
\begin{document}
...
\end{document}

我对此有一些疑问。首先,为什么写成\catcode`.13?我认为的语法\catcode应该=包含,表示字符及其新的类别代码。

第二,怎么就.因为类别码是13就可以成为命令本身了呢?这样的字符有很多,没有一个可以不以\开头就形成命令名。

答案1

分配中的=是可选的。实际上,使用 稍微更有效=,但优势很小。以收益\catcode`?13率为基准\catcode`?=13

No =
1.02e-7 seconds (0.472 ops)
With =
9.25e-8 seconds (0.427 ops)

我使用了l3benchmark多次重复代码,以便尽可能准确地给出估计值。顺便说一句,使用\active而不是13

No =
7.94e-8 seconds (0.378 ops)
With =
6.93e-8 seconds (0.327 ops)

一旦您将某个字符的 catcode 设置为 13(活动字符),它就会像一个控制序列一样运行,因此您可以将其用作后面的标记\def(或任何其他控制序列定义命令)来赋予它含义。

该功能可用于babel引入简写。例如,当当前babel语言为德语时,该组合"|表示词素边界,这对于打破不必要的连字非常重要,因此可以输入Auf"|lage清楚地表明该词是由“auf”和“lage”组成的。这是通过给出"catcode 13 并根据以下标记为其分配适当的定义来实现的:"-插入额外的换行符点,允许在其后进行连字符连接。

听起来很熟悉?是的,这和你的情况很相似,但有一个很大的区别:这个字符"在 TeX 中很少使用,但句点在很多地方都是 TeX 语法的一部分。

一旦你这样做\catcode`.=13,你将无法再指定

\vspace{1.5pt}

试试看。你需要说\vspace{1\string.5pt}。或者你可以用逗号代替句号。你愿意这么做吗?

好的,我们假设您是。这个想法是定义活动.以寻找下一个标记并决定要做什么。

在 LaTeX 中执行此操作的标准方法是使用\@ifnextchar,向其提供要查找的令牌以及在“成功”或“失败”时要执行的代码。

给定的定义打印一个句点(而不是\char`.我会做\string.)然后执行

\@ifnextchar'{T}{F}

(此处TF代表实际代码)。如果 TypeScript 中句点后面的字符是',则T执行,否则执行F。由于您不想执行任何操作,因此在本例中,T实际上是空的。如果' 没有执行后,F实际的代码是

\@ifnextchar.{}{ }

如果后面跟着句号,则不执行任何操作,否则会插入空格。为什么要进行此检查?我不确定,因为输入两个连续的句号并不常见,而三个句号是不正确的,因为\ldots应该使用。

无论如何,代码完成了它的工作。但是,假设您愿意接受上述几个问题\vspace{1.5pt},那么这并不是最好的编程。

\documentclass{article}

\makeatletter
% define the desired action for the active period
\begingroup\lccode`~=`.\lowercase{\endgroup
  \newcommand{\active@period}{.\@ifnextchar'{}{\@ifnextchar~{}{ }}}%
}
\AtBeginDocument{%
  % assign the meaning of \active@period to the active period
  \begingroup\lccode`~=`. \lowercase{\endgroup\let~}\active@period
  % change the catcode
  \catcode`.=\active
}
\makeatother
% to locally set the category code of . to 12
\newcommand{\Abbr}{\catcode`.=12 }% don't forget the space!

\begin{document}
...
\end{document}

这样,类别代码的设置就会延迟到文档开始时配置文件已经被读入的时候。

后面的空格12需要。 尝试

{\Abbr 1.2.3}

看看原始代码是否存在问题。事实上,你会得到

\catcode`.121.2.3

并且将 121 指定为 catcode 是非法的。如果使用空格,则

\catcode`.12 1.2.3

12并且根据 TeX 规则,后面的空格将被忽略。

采用更现代的方法:

\documentclass{article}

\ExplSyntaxOn

% to locally set the category code of . to 12
\NewDocumentCommand{\Abbr}{}{\char_set_catcode_other:N .}

% define the desired action for the active period
\cs_new_protected:Nn \youthdoc_active_period:
 {
  .
  \peek_charcode:NF .
   {% a period doesn't follow
    \peek_charcode:NF '
     {% a quote doesn't follow, insert a space
      \c_space_tl
     }
   }
 }
% at begin document set the period to be active
\AtBeginDocument
 {
  \char_set_active_eq:NN . \youthdoc_active_period:
  \char_set_catcode_active:N .
 }

\ExplSyntaxOff

\begin{document}

A period.With a space.But ...has a space only at the end

`A quote.'

\end{document}

在定义中,没有扭曲的句点具有不同的 catcode。

答案2

您显示的代码在每个点后插入空格,但有两个例外。如果点后跟字符'或字符后跟另一个点,则不会插入空格。

TeX 原始命令\catcode将类别代码(16 个值之一)分配给字符。语法是\catode <number>=<number>\catcode <number><number>(即 是=可选的)。第一个数字是计算机中字符的数字表示(ASCII 或 Unicode),第二个数字在 0 到 15 范围内,表示分配的类别代码。如果您知道点的数字表示(它是 46),那么您可以说 \catcode 46 13\catcode 46=13。您可以使用`后跟一个字符或\后跟一个字符代替数字常量,结果相同:\catcode`.=13\catcode`\.=13\catcode`.13\catcode`\.13

一旦字符具有类别代码 13,它就处于“活动”状态,这意味着它的行为就像另一个控制序列。您可以在、和许多其他情况下使用它\def<control sequence>\let<control sequence>\countef<control sequence>它被定义为宏时,在常见情况下,当 TeX 扫描仪到达时,字符会扩展到其主体。

PlainTeX 将类别代码 13 设置为 ,~并将其定义为一个宏,该宏将扩展为\penalty10000 \space,即不可中断的空格。PlainTeX 没有将其他可见字符设置为类别 13。其他 TeX 格式(如 LaTeX)也这样做:它们仅将类别 13 设置为~。您可以设置更多这样的字符,并在给出的代码中执行此操作。

这是一个 LaTeX 宏,它使用TeX 基元\@ifnextchar <character>{true}{false}查找下一个字符(但在输入队列中保持不变),如果下一个字符是则运行,否则运行。您可能想知道代码会做什么。\futurelettrue<character>false\@ifnextchar'{}{\@ifnextchar.{}{ }}

编辑\usepackage{expl3}评论中有一个新问题:如果不使用,为什么代码在新版本的 LaTeX 中不起作用。首先:您的宏与 expl3 没有任何共同之处,但新版本的 LaTeX 将 expl3 内容实现到 LaTeX 内核。并且它需要l3backend-?.def根据各种情况读取文件。如果您使用,则会立即读取此文件,但如果尚未读取,则会在新 LaTeX 内核中\usepackage{expl3}读取它。\begin{document}

读取外部宏文件需要只有标准 catcode 设置。在此状态下,点无法处于活动状态。这会导致错误。(注意:如果您使用 OpTeX\load加载外部宏,则不会出现此问题,因为它在读取此类文件时会临时设置标准 catcodes 向量。)

解决方案:您可以将带有活动点的宏放在后面\begin{document}。或者\catcode`.=12在宏代码的末尾设置,然后\catcode`.=13在之后\begin{document}或使用\AtBeginDocument宏再次设置。

相关内容