从技术上讲,在 T1 的宏名称中哪些字符是合法的?

从技术上讲,在 T1 的宏名称中哪些字符是合法的?

免责声明:我知道应该不是在宏名称中使用特殊字符,不建议这样做(相反)。我纯粹是出于好奇才问这个问题。


直到最近我才意识到宏名称中只能使用“普通”字符,即字母(a- zA- Z)和常见符号,如数字(0- 9)或标点符号(例如-!)。以下一个问题在这个网站上我发现事实并非如此:甚至允许使用重音字母(并且可以在使用时直接输入inputenc):

\documentclass{article}

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

\makeatletter

\begin{document}

\expandafter\def\csname \c c\v c\'e\endcsname{I am weird}
\csname \c c\v c\'e\endcsname:
\expandafter\string\csname \c c\v c\'e\endcsname

% with inputenc:
\def\äöü{Me too}
\äöü:
% \string\äöü does not work
\expandafter\string\csname äöü\endcsname

\end{document}

但是,有些字符(例如\v o或)会出错。另一方面,\ss输入ß(带有)则工作正常。令人惊讶的是,如果不使用 ,这根本不起作用。inputencfontenc


  • 您能给出一个关于哪些字符可以作为宏名称的精确规则吗?
  • \ss为什么书写和书写之间会有区别ß
  • 为什么\v c合法但\v o又不合法?
  • 为什么\def\äöü起作用了但是\string\äöü不行呢?
  • 为什么只有在使用时才有效\usepackage[T1]{fontenc}

答案1

您能给出一个关于哪些字符可以作为宏名称的精确规则吗?

绝对全部字节0 到 255 是允许在宏名称中使用的。但它们的输入是否方便,以及它们如何与人物在人类可见的意义上,除其他外,可以依赖于 catcodes 和活动字符的定义,而这些又可以依赖于当前加载的包(输入编码和字体编码)。

确切的规则是宏可以是:

  • 单一活跃角色:类别代码为 13,字符代码为 0–255 之间的任意数字的 token。

  • A控制字:转义字符 ( \) 后跟一串字母(以 11 作为类别代码、以 0-255 之间的任意数字作为字符代码的标记)。

  • A控制符号:一个转义字符 ( \),后跟一个非字母(以除 11 之外的任何内容作为类别代码,并以 0-255 之间的任意数字作为字符代码的标记)。


在回答您的其余问题之前,先做些解释。

与大多数软件系统一样,TeX(具体来说,非 Unicode TeX,即 Knuth TeX 或 pdfTeX,而不是 XeTeX 或 LuaTeX)仅理解字节(0 到 255);它不理解“字符”。 (与大多数 Unicode 之前的系统一样,其术语使用“字节”和“字符”有时会产生误导。)为了给人一种将字节“理解”为字符的错觉,会发生两种“翻译”:

  • 字体编码:这表示某些(我们所认为的)字符的形状(字形)在字体中“应该”位于何处:例如在默认(OT1)编码(并且还根据T1 编码), 位置 65 (八进制'101, 十六进制"41) 应该包含看起来像“A”的东西。而位置 231 (十六进制"E7) 应该包含 T1 编码中的“ç”字形,而不应该包含默认 (OT1) 编码中的任何内容。相应地,该包会根据需要fontenc重新定义 etc 的含义。\c

  • 输入编码:使用\usepackage[utf8]{inputenc},这会将某些字符(字节)设置为活动字符,以便 UTF-8 字节序列可以被解释为相应的 Unicode 字符。

另外:TeX 有一种方法可以在输入文件中直接输入特定字节,后跟^^两个十六进制数字(0123456789abcdef),例如在任何可以输入“A”的地方(在文本中、在宏名称中,等等),也可以输入^^41,等等。为了清楚起见,我们使用它。

基于这样的理解,问题中的两个例子是:

  1. \csname \c c\v c\'e\endcsname— 这里, 、 和的\usepackage[T1]{fontenc}定义如下\c\v\'

    • \c ce7扩展为类别代码为 11、字符代码为 231(十六进制)的标记,
    • \v ca3扩展为类别代码为 11、字符代码为 163(十六进制)的标记,
    • \' e扩展为类别代码为 11、字符代码为 233(十六进制)的标记e9

    因此以下是等效的:

    \expandafter\def\csname \c c\v c\'e\endcsname{I am weird}
    

    {\catcode"E7=11 \catcode"A3=11 \catcode"E9=11
     \expandafter\def\csname ^^e7^^a3^^e9\endcsname{I am weird}}
    

    并且简单地

    {\catcode"E7=11 \catcode"A3=11 \catcode"E9=11
    \def\^^e7^^a3^^e9{I am weird}}
    

    这是一个“控制字”类型的宏:反斜杠后跟三个字母的序列。

  2. 这里,äöü输入文件中(假设您已将文件保存为 UTF-8 编码)的字节序列为 C3 A4 C3 B6 C3 BC。此外,\usepackage[utf8]{inputenc}将所有这些字节的 catcode 更改为 active。因此,以下两个是等效的:

    % Assuming UTF-8 inputenc
    \def\äöü{Me too}
    

    {\catcode"C3=13 \catcode"A4=13 \catcode"B6=13 \catcode"BC=13 % Same as those set by \usepackage[utf8]{inputenc}
    \def\^^c3^^a4^^c3^^b6^^c3^^bc{Me too}}
    

    这是一个“控制符号”类型的宏:它实际定义的是\^^c3(一个非字母),要求在使用它时,它后面必须跟着^^a4^^c3^^b6^^c3^^bc所有 catcode 13 的标记。(否则你会得到类似的结果Use of \^^c3 does not match its definition。)

现在回答您其余的问题:


为什么\v c合法但\v o又不合法?

  • \v c扩展为类别代码为 11(字母)且字符代码为 163(十六进制)的标记"A3。您可以看到这是字符č 在T1

  • \v o不会扩展为单个字符标记(T1 编码中有一个č但没有ǒ),而是扩展为向字符添加适当重音的​​指令o。在 中\csname ... \endcsname,所有内容都应扩展为字符标记。


\ss为什么书写和书写之间会有区别ß

实际上没有太大的区别;只是你(我猜)在 内部尝试了前者\csname … \endcsname,并在 之后直接尝试了后者\def

与之前的情况不同,例如,\c c扩展为类别代码为 11、字符代码为 231 的单个标记,\ss扩展为\char"FF— 即 TeX 原始命令\char,后跟(如果\char正在处理)数字"FF。 (这与标记 不同^^ff,尽管我不知道为什么fontenc不定义\ss扩展为单个字符标记。)这在 中也是不允许的\csname … \endcsname

ßtoo 会扩展为类似的东西(你也不能在里面使用它\csname … \endcsname),但是如果你\def直接在之后使用它,那么没有扩展它就是两个活动字符的序列^^c3^^9f,并且\def不会扩展标记。


为什么\def\äöü起作用了但是\string\äöü不行呢?

请参阅上文了解其\def\äöü工作原理:它是\def\^^c3^^a4^^c3^^b6^^c3^^bc

并且\string\äöü是(有效:试试看)后跟(并且那里的第一个字节,\string\^^c3^^a4^^c3^^b6^^c3^^bc即的 UTF-8 表示的第二个字节,已被定义为引发错误的活动字符,因为它永远不应该在有效的 UTF-8 中单独出现)。\string\^^c3^^a4^^c3^^b6^^c3^^bcä


为什么只有在使用 \usepackage[T1]{fontenc} 时才有效?

控制符号的定义(如\def\äöü{Me too})无论有没有 都可以使用\usepackage[T1]{fontenc},其用法也是如此。但是,如果您想在 内使用这些“特殊”字符\csname ... \endcsname,则需要将其定义扩展为字符标记(确实\usepackage[T1]{fontenc}可以,因为它可以:这些字符存在于字体中),而不是扩展为将重音符放在其他字符上方/下方的指令(如果没有 就会发生这种情况\usepackage[T1]{fontenc},因为没有其他选择)。

答案2

基本上没有。有些可以,有些则不一定。

对于 来说\v c,最终的扩展名是代码为 163 的字符;对于 来说\ss,最终的扩展名是\char"FF,这在 内部是非法的\csname...\endcsname

\def\äöü没有定义这样的命令,而是定义了一个以字符编号和为名称的控制符号0xC3,其后必须跟有代码为0xA40xC30xB60xC3的字符0xBC(您应该能够识别äö和的 UTF-8 表示形式ü)。

事实上,当您这样做时\string\äöü,您会得到一个错误,因为字符0xA4出现孤立(的UTF-8表示中的第一个字节ä已被吸收\string),所以它会引发有关格式错误的UTF-8序列的错误。

最终结果几乎是任意错误的。

相关内容