免责声明:我知道应该不是在宏名称中使用特殊字符,不建议这样做(相反)。我纯粹是出于好奇才问这个问题。
直到最近我才意识到宏名称中只能使用“普通”字符,即字母(a
- z
,A
- 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
输入ß
(带有)则工作正常。令人惊讶的是,如果不使用 ,这根本不起作用。inputenc
fontenc
- 您能给出一个关于哪些字符可以作为宏名称的精确规则吗?
\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
,等等。为了清楚起见,我们使用它。
基于这样的理解,问题中的两个例子是:
\csname \c c\v c\'e\endcsname
— 这里, 、 和的\usepackage[T1]{fontenc}
定义如下\c
,\v
\'
\c c
e7
扩展为类别代码为 11、字符代码为 231(十六进制)的标记,\v c
a3
扩展为类别代码为 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}}
这是一个“控制字”类型的宏:反斜杠后跟三个字母的序列。
这里,
äöü
输入文件中(假设您已将文件保存为 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
,其后必须跟有代码为0xA4
、0xC3
、0xB6
和0xC3
的字符0xBC
(您应该能够识别ä
、ö
和的 UTF-8 表示形式ü
)。
事实上,当您这样做时\string\äöü
,您会得到一个错误,因为字符0xA4
出现孤立(的UTF-8表示中的第一个字节ä
已被吸收\string
),所以它会引发有关格式错误的UTF-8序列的错误。
最终结果几乎是任意错误的。