更多细节

更多细节

我们必须避免的过时软件包和类的列表,我发现了两个术语,即 font-encoding 和 input-encoding。它们之间有什么区别?

答案1

存储在计算机中的文件只是 0-255 范围内的数字序列。当您将文件作为程序的输入时,该程序必须知道如何解释此数字序列。文本编辑器将根据明确定义的规则(我称之为“代码页”)将特定字形与每个数字(或数字子序列)关联起来,从而解释文件。

在过去,允许的数字范围是 0–127,并且只有一个代码页,即 ASCII(实际上,某些系统使用另一种称为 EBCDIC 的方法,但这不太相关)。当然,如此有限的范围使得无法表示使用重音符号、变音符号或与基本拉丁字母完全不同的字母的语言所需的字符。因此开发了许多代码页,以不同的方式填充范围 128–255。

TeX 使用的解释方式与文本编辑器不同:它读取的数字受标记化过程,以便控制序列可以与普通字符区分开来。但最后,TeX 排版字符,当 TeX 被告知“排版字符号X",它会输出在位置找到的字形X当前字体。

最初的 TeX(版本 2)实际上只能理解 0-127 范围内的输入,但可以管理具有 256 个字形的字体,因为某些数字序列可以通过当前字体度量文件中包含的信息映射到字形(这仍然是---映射到长破折号的方式)。这种方法对于管理不同的语言来说并不实用,因为它需要每个代码页都有不同的度量文件。在 TeX3 中,情况有所改变,因为所有 0-255 范围内的输入都合法了,但它仍然没有解决不同代码页使用不同度量文件的问题。

因此,LaTeX 开发团队制定了一项新策略。您可以向 LaTeX 宣布要使用哪个代码页进行输入(例如latin1koi-8r)以及输出所需的代码页。开发了一些标准输出代码页:T1、T2A、T2B、T2C、T3、T4;第一个用于拉丁字母,T2*x* 用于西里尔字母,T3 用于 IPA,T4 用于非洲拉丁字母。

该方法通过提供一个中间层来工作,称为 LaTeX 内部字符表示 (LICR)。每个输入字符都会根据开头给出的信息进行更改

\usepackage[<codepage>]{inputenc}

映射到 LICR;例如,àLatin-1 代码页中 对应的数字被映射到\`a。反过来\`a,当当前输出编码为 T1 时, 被映射到单个字形;当当前输出编码为 T2A 时, 被映射到一组较低级别的 TeX 指令,用于在 上打印重音符a

具有有限数量的输出代码页是必要的,以避免需要为每个输入代码页开发字体文件,同时保持正确连字的可能性:TeX 只能对由相同字体的字符形成的单词进行连字,而不包含“构建”的字形,例如基本字符上的重音符号。

随着 Unicode 和 UTF-8 的出现,情况发生了一些变化,UTF-8 是一种用从计算机文件中读取的一到四个数字序列来表示 Unicode 的方法。当你说

\usepackage[utf8]{inputenc}

您基本上摆脱了输入编码“仅 256 个字符”的限制,但输出编码仍然存在限制。因此,您不能指望 LaTeX 能够正确解释使用拉丁文、西里尔文、梵文和中文等混合输入,除非正确分离每个部分以使用正确的输出编码。

例如,用意大利语和俄语编写的文档将使用babel环境和命令在语言之间切换,并隐式地在输出代码页之间切换。因此,如果有人宣布

\usepackage[italian,russian]{babel}

基本语言将是俄语,默认输出代码页将是 T2A(由 自动选择babel)。\foreignlanguage{italian}{parola}找到后,代码页将暂时更改为自动选择的意大利语代码页。不幸的是,这会带来一个问题:出于兼容性原因,默认输出代码页仍然是只有 128 个字形的“原始 TeX”,因此在这种情况下最好说

\usepackage[T1,T2A]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[italian,russian]{babel}

这样意大利语部分将使用包含重音字符的 256 字形字体。

如果一个人只说俄语\usepackage[utf8]{inputenc}而不向别人念俄语babel,则在尝试使用西里尔字符时会出现许多“未定义字符”的错误,因为这些字符与当前字体中的任何内容都不对应。

重要的提醒

用于编写 LaTeX 文档的编辑器是不是TeX 或 LaTeX。您必须注意编辑器使用的输入映射与 LaTeX 使用的输入映射相对应。没有关于如何确保这种等效性的一般建议,因为每个编辑器对此都有自己的想法。

最好的建议是:始终使用 UTF-8

答案2

Your text --------------->  TeX   --------------> PDF
          input encoding           font encoding

你需要一个输入编码要告诉 TeX 如何解释文本文件的内容,你需要一个字体编码正确连字。旧版 TeX 只能将来自同一字体的单词连字,因此您需要将使用的所有字符(包括所有重音字符)压缩到同一字体中。如果您需要在一个单词中使用超过 256 个不同的字符,那么您就没那么幸运了。

所以输入编码非常重要,因为错误的输入编码会使 TeX 无法正确解释文本。字体编码并不那么重要,只要你的所有角色都表现出来就行。例如T1(== ec,tex256)编码被广泛使用,但也有其他编码,例如原始OT1字体编码。

更多细节

当你写德语文本时,你会很快了解输入编码和输出编码。假设你想写单词draußen(意思是“外面”)。 不在ßASCII 码中,因此对于 8 位编码(例如 Windows Ansi 或 Latin1),每个编码的代码ß都不同。为什么这是个问题?如果你想ß在你的 PDF 中出现,TeX 需要在输出中放入一条不同的信息。

输入编码

假设 TeX 想要使用字节“255”作为ß。因此你需要一个映射

my input code ---> \ss  ----> 255  

假设您使用 latin1 输入法(因为它曾经是 Linux 的标准输入法)。单词“draußen”在您的硬盘上保存为字节 100、114、97、117,223,101,110,以及latin1.def定义:\DeclareInputText{223}{\ss}所以当它看到字节223它会将其转换为\ss(即输入编码)。如果您使用带有代码页 850 编码的 Windows 计算机,则字节序列为 100、114、97、117,225,101,110,你需要一个不同的映射(cp850.def使用的文件\DeclareInputText{225}{\ss}

字体编码

但是 TeX 怎么知道该如何处理\ss? 当你加载 T1 fontencoding 时它定义:

\DeclareTextSymbol{\ss}{T1}{255}

\ss因此,这就是 TeX在输入中遇到 时选择字节数 255 的神奇部分。但这就是全部吗?不,当然不是。PDF 格式需要将字节 255 映射到字形!这在编码文件中完成,例如tex256.enc

/T1Encoding [
/grave %        0
/acute %        1
/circumflex %   2
...
/udieresis %    252
/yacute %       253
/thorn %        254
/germandbls %   255
] def

字体被重新映射,因此字节 255 与名为 的字形匹配/germandbls

变得更加丑陋

通过使用虚拟字体在内部重新映射编码,你甚至可以让事情变得更糟。这是普斯福斯包。但我不在这里给出详细信息,因为这无助于理解 inputenc/fontenc 主题。

答案3

输入编码是在输入端,也就是说,将输入文件中的字符正确地输入到 (La)TeX 中。字体编码是在输出端,也就是说,“我想打印一个‘A’,在我的字体中我应该在哪里找到它?”

答案4

在我的回答中希腊文本我给出了一个解释,我将在这里重复并扩展它。我在这里主要讨论文本编码,因为很明显数学需要特殊处理。

另请查看指南其中对这一切进行了更详细的解释。

首先,所有这些都涉及 TeX 引擎,pdftex其仅支持字体端的输入 8 位编码。

这意味着引擎只能理解输入文本中的 256 个不同字符,并且以给定的字体最多输出 256 个不同的字符。

对于像 LuaTeX 和 XeTeX 这样的 16+ 位感知系统,所有这些都无关紧要。

即使不考虑中文等,256 个字符对于表达所有字符来说也太少了,这并不奇怪。指南有一些代码表,看看 T1 的表(在某种意义上是“标准”),很明显它已经完全塞满了,而且仍然缺少一些字符。T1 代表了努力挤进欧洲语言所需的每个字符,但它仍然缺少一些波兰语或立陶宛语的特殊字符,例如,希腊语或俄语就更不用说了。

那么,生成可包含超过 256 个不同字符的文档的策略是什么呢?答案当然是字体编码. 基本上,这意味着

  1. 每种编码都有专用的字体,在正确的位置包含该编码指定的 256 个字符。
  2. 一些 LaTeX 内部结构被重新定义以适应编码。

请注意,当使用可包含超过 256 个字符的 PostScript 或 TTF 或 OTF 字体时,对于不同的编码,不一定需要不同的字体,TeX 提供了“虚拟字体”作为中间概念。但我对这些一无所知 ;-)

回到编码。当我说,例如,内部会发生什么\fontencoding{T2A}\selectfont

  1. 在内部,字体将切换为适合此编码的字体。也就是说,字体内的字符将位于此编码指定的位置。
  2. 一些 LaTeX 内部结构将会切换其含义,以便文本输出能够映射到正确的字体字符。

后者是如何实现的?

<encname>enc.def每种字体编码都与一个包含如下定义的文件相关联。\fontenc[<encname>]{fontenc}发布声明时会自动加载该文件。

t1enc.def

\DeclareTextSymbol{\AE}{T1}{198}
\DeclareTextSymbol{\DH}{T1}{208}
\DeclareTextSymbol{\DJ}{T1}{208}
\DeclareTextSymbol{\L}{T1}{138}
\DeclareTextSymbol{\NG}{T1}{141}
\DeclareTextSymbol{\OE}{T1}{215}
\DeclareTextSymbol{\O}{T1}{216}
\DeclareTextSymbol{\SS}{T1}{223}
\DeclareTextSymbol{\TH}{T1}{222}
\DeclareTextSymbol{\ae}{T1}{230}
\DeclareTextSymbol{\dh}{T1}{240}
\DeclareTextSymbol{\dj}{T1}{158}

来自 t2aenc.def:

\DeclareTextSymbol{\CYRZH}{T2A}{198}
\DeclareTextSymbol{\cyrzh}{T2A}{230}
\DeclareTextSymbol{\CYRZ}{T2A}{199}
\DeclareTextSymbol{\cyrz}{T2A}{231}
\DeclareTextSymbol{\CYRI}{T2A}{200}
\DeclareTextSymbol{\cyri}{T2A}{232}

这意味着,例如,控制序列\AE将被定义为当字体编码 T1 处于活动状态时,则产生字符号 198。\DeclareTextSymbol同一控制序列可以有多个声明,但编码方式不同,例如 LY1 编码定义

\DeclareTextSymbol{\L}{LY1}                 {128}

因此,波兰语 Ł 在具有各自编码的字体中位于不同的位置,但 LaTeX 会在内部对其进行分类。

基本上,这意味着 LaTeX 可以在内部处理任意数量的不同文本字符,但只能输出当前活动字体编码中可用的字符。

但是这里定义的控制序列(例如\AE或)来自哪里?\CYRZH

当然,您始终可以将它们输入为控制序列,但是当您用特定语言编写文本时,您当然希望能够直接输入键盘上可用的字符。

这由输入编码。为方便起见,输入编码是基于“代码页”来组织的,这些代码页在使用 8 位输入方案的计算机系统上是(或曾经是)常见的,即 ISO 8859-<something>(latin在 LaTeX 中称为 <something>),applemacansinew

在文本编辑器中输入特定代码页激活的文本意味着通过输入某个字符,其相关代码对于该代码页写入文本文件。

要向 LaTeX 声明某个代码页,存在一个<code page name>.def包含如下声明的文件。\inputenc[<code page name>]{inputenc}发布声明时会自动加载该文件。

latin1.def

\DeclareInputText{198}{\AE}
\DeclareInputText{214}{\"O}
\DeclareInputText{199}{\c C}
\DeclareInputMath{215}{\times}

iso88595.def

\DeclareInputText{198}{\CYRC}
\DeclareInputText{199}{\CYRCH}
\DeclareInputText{200}{\CYRSH}
\DeclareInputText{201}{\CYRSHCH}
\DeclareInputText{202}{\CYRHRDSN}
\DeclareInputText{203}{\CYRERY}
\DeclareInputText{204}{\CYRSFTSN}

\AE从内部来看,这意味着当latin1输入编码处于活动状态(意味着 ISO 8859-1)和\CYRCiso88595输入编码处于活动状态(意味着 ISO 8859-5)时,输入字符 198 将产生控制序列。

我希望这能澄清一切。

相关内容