> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/zh-cn/shen-ru-wen-zhang/51-unicode-utf-8-and-multilingual-text-an-introduction.md).

# Unicode、UTF-8 和多语言文本：简介

## Unicode 和 OpenType：字符与字形

现代 TeX 引擎，即 XeTeX 和 LuaTeX，已从 Knuth 最初的 TeX 引擎演变而来，主要是为了跟上技术环境的发展，尤其是 Unicode（用于文本）和 OpenType（用于字体）。如今，通过使用诸如 [fontspec](https://ctan.org/pkg/fontspec?lang=en) 和 [unicode-math](https://ctan.org/pkg/unicode-math?lang=en)之类的宏包，LaTeX 用户可以访问 OpenType 字体提供的极其先进的排版能力——包括高级多语言排版以及基于 OpenType 的数学排版（[由 Microsoft 首创](https://blogs.msdn.microsoft.com/murrays)).

然而，要想充分利用 XeTeX/LuaTeX 搭配 OpenType 字体，熟悉一些背景主题/概念会很有帮助——尤其是在排查问题，或为更高级/更复杂的工作铺路时。例如，你可能会读到 XeTeX 和 LuaTeX 引擎使用“UTF-8 输入”，或者说它们是“Unicode 感知”的，而进一步阅读 OpenType 字体时，可能会讨论或提到“Unicode 编码”、“OpenType 字体特性”、“字形”、“字形 ID”、“字形名称”等主题。我们的目标是介绍这些术语/主题，并拼接出一个基本框架，说明它们彼此如何关联，并希望能为后续工作或问题解决提供支持。

我们打算涵盖的主题大致可清晰地分为两大领域： *Unicode* 它实际上属于文本/字符和文本编码的世界，并且 *OpenType* 它的世界是字体和字形；当然，这两个世界是相互关联的，即使在这篇开篇文章中也存在一些交叉。

### 我们要讨论哪些主题？

本文的重点是一些与 Unicode 相关的主题：先讨论“字符”是什么意思，再介绍文字系统/语言、Unicode 编码和 UTF-8——并辅以一个处理多语言文本文件的示例。后续文章将在此基础上展开，介绍与 OpenType 字体技术相关的背景主题。显然，在一篇博客文章的篇幅内，不可能对我们希望讨论的所有领域进行“深度探讨”：我们声明的目标是提供一个总体框架，说明若干关键概念如何相互关联并协同工作。我们将从最基本的概念开始：也就是 *字符*.

## 字符：一个基本构件

我们讨论的核心（以及 Unicode 的核心）有一个基本概念/思想，那就是“字符”的含义：这是一个在日常工作和对话中常常会通过用法而“默认理解”的词。然而，从 Unicode、排版和字体技术的角度来看，我们需要更精确一些，定义“字符”究竟是什么意思。例如，我们很自然地会把 **a** 和 *a* 看作不同的“字符”：‘粗体 a’和‘斜体 a’。但并非如此：它们只是同一个基本字符的不同视觉呈现，而 Unicode 给它的正式名称是 [拉丁小写字母 a](http://unicode.org/charts/PDF/U0000.pdf).

Unicode [定义字符](http://www.unicode.org/glossary/#character) 为：

> “书面语言中最小的具有语义价值的组成部分；指的是抽象的含义和/或形状，而不是某个具体形状……”

清楚地区分了字符的具体 *视觉外观* 与其 *含义*.

你可以把字符看作语言的基本单元，或构件，更准确地说，是一种 *文字体系*——这是我们下面要讨论的话题。字符在特定字体下显示时究竟是什么样子，并不属于 Unicode 对字符的定义范围：真正值得关注的只有 *含义* 这里真正值得关注的是： *作用和目的* 作为一组构件中的每个字符，文字系统/语言最终正是由这些构件构成的。

### 文字系统与语言

值得简要提及两个重要概念： *文字系统* 和 *；或者用于阿拉伯语和波斯语（Farsi）的阿拉伯字母。*。Unicode 网站提供了一个 [对文字系统的定义](https://www.unicode.org/standard/supported.html):

> “Unicode 标准编码的是文字系统，而不是语言。当用于多个语言的书写系统共享一组在历史上彼此相关的图形符号时，这些图形符号的并集会被视为一个单独的字符集合进行编码，并被识别为一个单独的文字系统。”

使用一个 [Wikipedia 上的一个示例](https://en.wikipedia.org/wiki/Script_\(Unicode\))，拉丁文字系统由一组特定的 [字符集合](http://unicode.org/charts/) ，这些字符被用于多种语言：英语、法语、德语、意大利语等等。当然，拉丁文字系统中定义的并非所有字符都被所有基于拉丁文字系统的语言使用——例如，英语字母表不包含法语或德语等其他欧洲语言中出现的带重音字符。

### OpenType 字体：文字系统和语言

在这一点上，我们将从 Unicode 过渡到 OpenType 字体，因为文字系统和语言的概念在 OpenType 字体技术中也扮演着极其重要的角色。

使用同一种 [文字体系](http://www.unicode.org/glossary/#script) 的语言集合，在显示（排版）某种特定语言文本时，可能各自有不同的排版传统。一个很好的例子是土耳其语和 [无点 i 的行为](https://en.wikipedia.org/wiki/Dotted_and_dotless_I) （参见该页关于连字的注释）。与文字系统/语言相关的排版“规则”通过所谓的文字系统和语言 *标签* 来构建到 OpenType 字体的功能中，这些规则用于标识应适用于特定文字系统/语言组合的规则。自然地，每种 OpenType 字体支持的文字系统/语言集合会因字体创作者的选择及其制作目的而异。像 XeTeX 或 LuaTeX 这样的高级排版软件，可以利用这些规则（内置于 OpenType 字体中），通过允许用户在排版某种特定语言文本时有选择地将它们应用于输入文本——例如，通过使用 LaTeX [fontspec 宏包](https://ctan.org/pkg/fontspec?lang=en).

#### 查看 OpenType 字体内部：文字系统/语言

为了更清楚地说明这一点，这里有一张截图，展示了免费的 [Scheherazade OpenType 字体](http://software.sil.org/scheherazade/download/) 在同样免费的 [Microsoft VOLT](https://www.microsoft.com/en-us/Typography/volt.aspx) 字体编辑软件中打开后的样子。在这张图中，你可以看到内置于 Scheherazade 的文字系统、语言和排版特性——使用 VOLT，你可以为 Scheherazade 添加额外的特性和功能，但这已经远远超出本文的范围了！

![在 Microsoft VOLT 中打开的 Scheherazade OpenType（TrueType 风格）字体](/files/cf18d85c3e4d4501ef41aa252eb35dcd7b2bb183)

从这张截图可以看出，Scheherazade 支持阿拉伯和拉丁文字系统，并为若干使用阿拉伯文字系统的语言提供进一步的专门支持——通过上面绿色边框框出的所谓 OpenType 特性。我们不会深入讲解这些特性的细节，但这里要传达的信息是：高质量的 OpenType 字体内部内置了大量“智能”，可供能够利用字体内置排版规则的排版软件使用。

有兴趣的读者可以浏览 OpenType 标记注册表，查看当前在 OpenType 规范中使用的 [文字系统标记](https://www.microsoft.com/typography/otspec/scripttags.htm) 和 [语言标记](https://www.microsoft.com/typography/developers/opentype/languagetags.aspx) 。

### 回到字符：不同的字符角色

构成文字系统（或语言）基本元素的字符集合，并非每个字符都承担同样的角色。例如，在大多数语言中都有用于 *标点符号*的字符，以及表示数字的 *数字* 字符，还有我们认为是 *字母* 字母表中的字符，而对于某些文字系统，这些字符还存在大写和小写形式。字符的概念相当宽泛，Unicode 标准还包括一些专门字符，它们 *并非为显示而设计* ，而其职责是“控制文本的解释或显示”。例如，在排版某些阿拉伯文本时，你可能希望强制某些字符连写，或者阻止它们连写；Unicode 标准提供了特殊控制字符来做到这一点：即所谓的 [零宽连接符](https://en.wikipedia.org/wiki/Zero-width_joiner) 和 [零宽非连接符](https://en.wikipedia.org/wiki/Zero-width_non-joiner)。这些字符并非用于显示，在处理文本以产生预期的视觉效果时，会被软件“吸收”。

Unicode 标准中指定的所有字符都被分配了一组属性，实际上这些属性描述了 Unicode 编码中每个字符的作用和目的——字符名称，例如 LATIN SMALL LETTER A，只是字符属性列表中的一个元素。这些属性在 [Unicode 字符数据库（UCD）](http://www.unicode.org/reports/tr44/) 中有完整描述，并广泛用于计算机文本处理操作，例如搜索、排序、拼写检查等。列出 Unicode 字符属性的数据文件也可 [供下载](http://www.unicode.org/Public/UCD/latest/).

在分配给每个字符的属性中，与我们的讨论最相关的是一个 *数字标识符* ，它由其 Unicode 编码分配；我们现在就来转向这个话题。

### 字符：数字与编码

这显然是常识，但计算机和其他数字设备本来就是用来存储和处理数字数据的：那这和文本有什么关系呢？当你使用电脑键盘输入一些文本，或者在移动设备屏幕上点按时，你的按键操作会被转换成数字，这些数字代表你正在输入的字符序列。

在某个时刻，你可能希望通过电子邮件、短信，或者通过在线通信，例如推文或某种社交媒体上的帖子，传输那段文本（一个数字序列）。显然，编写文本的设备和其接收者使用的设备必须以某种方式就哪些数字代表哪些字符达成一致。否则，你的文本在接收者设备上的显示可能不正确。

为了让当今的全球通信得以运作，发送和接收设备需要某种“双方共同约定的约定”，通过它一组特定的数字代表一组特定的字符。这种约定称为 *编码*编码：一组用于表示某组特定字符的数字，而 Unicode 编码如今是 *事实上的* 全球标准。

## Unicode：用于存储文本的比特与字节

Unicode 是一个极其庞大的标准，涵盖的远不止文本编码，但这里我们只关注它提供的编码。

#### 比特、字节，以及能容纳多少字符？

我们提到过，设备将文本存储并表示为数字——更具体地说，字符会被存储为整数：也就是整数。要理解这对 Unicode 编码的影响，我们需要对计算机如何存储整数做一个 *非常* 简短的、 *非常* 基础的回顾（我们无意深入计算机科学）。

长话短说，如今的台式或便携设备会以离散的“块”来存储整数，这些块可以是 1、2、4 或 8 个字节长。每个这样的存储单元都能根据其包含的总比特数存储到某个最大正整数：

* 1 字节（8 比特）：最大正整数为 255；
* 2 字节（16 比特）：最大正整数为 65535；
* 4 字节（32 比特）：最大正整数为 4,294,967,295；
* 8 字节（64 比特）：最大正整数为 18,446,744,073,709,551,615。

实际上，Unicode 标准使用 0 到 1,114,111 之间的数字来编码世界上的所有字符，因此只需 21 比特就能编码完整范围。我们可以通过注意到含有 n 比特的存储单元可表示从 0 到最大值 $$2^n -1$$；因此：

* 20 比特可存储的最大值是 $$2^{20} -1 = 1,048,575$$ （太小）；
* 21 比特可存储的最大值是 $$2^{21} -1 = 2,097,151$$ （足够大）。

我们已经注意到，计算机以 1、2、4（或 8）字节为单位存储数据（数字），那么如果我们必须存储最高 Unicode 值 1,114,111 以内的值，存储单元需要多大呢？显然，字节大小的存储单元最大值只能是 255，而 2 字节可存储 65535：这两者都不足以存储 Unicode 编码的完整字符范围。下一个可用选项是 4 字节大小的存储单元，它可以存储高达 4,294,967,295 的整数，这远远超过我们实际所需。因此，如果我们选择 4 字节作为存储单元，当然足以存储所有 Unicode 值，每个字符都将作为一个需要 4 字节（32 比特）的整数来存储。然而，使用 4 字节存储一切会非常浪费空间，因为即使是最大的 Unicode 值也只需要最多 21 比特——如果用 32 比特存储，就意味着那 32 比特中的 11 位永远不会被使用。

**注意**：尽管 Unicode 的范围从 0 到 1,114,111，但该范围内的并非每个值实际上都被使用：出于技术原因，有些值被视为不适合实际用作 Unicode 字符。

### 那么，什么是 UTF-8？

如果你读过有关 XeTeX 或 LuaTeX 的资料，你几乎一定会遇到这样的说明：这些 TeX 引擎以“UTF-8 格式”读取文本和 LaTeX 输入文件。那么什么是“UTF-8 格式”，它与 Unicode 有什么关系？在 Unicode 术语中，用于编码世界字符的 0 到 1,114,111 之间的 1,114,112 个值中的每一个都称为一个 [码位](http://www.unicode.org/glossary/#code_point).

我们已经看到， *在理论上*，为了表示 Unicode 的完整码位范围，我们需要用每个字符 4 字节来存储所有 Unicode 编码文本。然而，在实践中，一些非常聪明的人发明了一种简单的方法，把单个 Unicode 数字（码位）表示为一个 *序列* 更小的数字序列，其中每个更小的数字都存储在一个字节中：这一过程 *把* 一个单独（较大）的整数转换为一串较小的（字节大小的）整数。由于这种转换，我们文本文件中的字符不再各自对应一个数字值：每个字符都变成了一个 *多字节序列*——文本文件中 1 到 4 个（连续的）字节都可以表示一个单独的 Unicode 字符（即其码位值）。

UTF 代表 *Unicode 转换格式* ，这里的关键词是 *转换*。本质上，你可以把 UTF-8 看作一种“配方”或算法，用于将单个 Unicode 码位值转换为 1 到 4 个字节大小的片段序列。Unicode 码位值越大，在 UTF-8 格式中表示它所需的单字节数量也越多。

创建 UTF-8 有技术和历史原因，而 UTF-8 发明背后的故事 [记录在一封 2003 年的精彩电子邮件中](https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt)，这封邮件在开头附近包含这样一句话：

> “这不是真的。UTF-8 是 1992 年 9 月左右的某个夜晚，当着我的面，在新泽西一家餐馆的餐垫上设计出来的。”

#### 示例：阿拉伯字母 ل

让我们以阿拉伯字母 ل（Unicode 名称 ARABIC LETTER LAM）为例，它分配到的 Unicode 码位值是 1604（十进制）或 0644（十六进制）：它在 UTF-8 中的表示是 *双字节* 序列 D9 84（十六进制）或，十进制下为 217 132。当使用 UTF-8 作为文本存储格式时，与其用一个文本文件中的单个数字 1604 来表示 ل，不如将其转换为两个字节大小的值：217 和 132——字符 ل 被存储为一个 *双字节序列*。想更详细探索 UTF-8 算法的读者，可以在我的 [个人博客网站](http://www.readytext.co.uk/?p=1284).

当某个软件（例如 XeTeX 或 LuaTeX）以 UTF-8 格式读取文本时，该软件需要确定该文件中每个字符的 Unicode 值，因此它会使用一种算法来 *反向* UTF-8 转换过程反转。通过那种“反向算法”，这两个字节（217 和 132）会被重新组合，生成整数 1604，而它随后就能被识别为阿拉伯字母 ل 的 Unicode 码位值。

所以，总之，UTF-8 实际上只是一种中间数据格式，用于存储和传输 Unicode 编码的文本。

**注意**：有些系统选择使用每个字符 32 比特来存储文本，这被称为 [UTF-32](https://en.wikipedia.org/wiki/UTF-32)——另外还有 [UTF-16](https://en.wikipedia.org/wiki/UTF-16) ，但 UTF-8 是存储 Unicode 编码文本最常见的方式。

## 多语言 TeX 文件：XeTeX 和 LuaTeX

XeTeX 和 LuaTeX 都能够进行非常复杂的多语言排版，尽管它们实现这一点的机制相当不同，反映了各自引擎的设计/开发理念。我们不会深入探讨这一点，只指出 XeTeX 引擎包含一些软件组件（内置于其可执行文件中），而 LuaTeX 中没有——最显著的是用于一个称为 *OpenType 整形* （例如，通过一个名为 [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/)).

相比之下，LuaTeX 采用了不同的方法：它不是把功能直接构建到真正的 TeX 引擎中，而是提供了极其丰富的一组命令（TeX 原语）以及一个非常强大的 [基于 Lua 的 API](/latex/zh-cn/shen-ru-wen-zhang/07-an-introduction-to-luatex-part-1-what-is-it-and-what-makes-it-so-different.md) ，开发者可以借此构建同样先进的多语言排版解决方案。尽管 LuaTeX 的理念可能会给 LaTeX 宏包开发者带来额外工作，但它提供了更大的灵活性，因为解决方案并不是“硬编码”到 LuaTeX 引擎本身中，而是由 TeX 和 Lua 代码——或者用 C/C++ 编写的插件——构建而成。

**补充说明**：希望进一步探索 OpenType 整形这个迷人但复杂世界的读者，可能会有兴趣了解那个出色的开源库 [HarfBuzz](https://www.freedesktop.org/wiki/Software/HarfBuzz/)——它被包括 Firefox、Chrome 和 LibreOffice 在内的许多应用程序使用，当然 XeTeX 也在使用。本文作者曾利用 HarfBuzz 创建 [用于阿拉伯排版的 LuaTeX 插件](http://www.readytext.co.uk/?p=3186).

如今（例如在社交媒体上）传输包含多种语言字符的文本已很常见，而存储多语言文本的 UTF-8 文本文件很容易包含其 UTF-8 表示长度为 1、2、3 或 4 字节的字符。因此，从效果上说，UTF-8 文本文件只是一串单字节流，但文件中的每个实际字符都可能长达 1 到 4 个字节：单个字符已经变成了 *多字节序列*.

为了进一步探究处理（排版）多语言文本的一些关键方面，我们将使用一个包含阿拉伯文字系统的示例，因为阿拉伯语为我们提供了讨论多个概念的空间。

#### 补充说明：阿拉伯文字系统

该 [阿拉伯文字系统](https://en.wikipedia.org/wiki/Arabic_script) 采用连笔体书写，从右向左阅读和书写。每个阿拉伯字母都可能根据以下情况采用 4 种不同形状之一：

* 它是否以单独、独立（孤立）的字符形式显示（不与任何其他字符连写）；
* 它是否出现在一个词中——词首、词中或词尾：分别称为 *词首*, *词中* 和 *final* 形式。

阿拉伯文字系统中的每个字符都有自己的一套连写规则，并且当其左侧、右侧，或左右两侧有另一个字符时，可能会或可能不会改变形状/外观。对此感兴趣、希望进一步探索的读者可以找到一个 [维基百科上的完整列表](https://en.wikipedia.org/wiki/Template:Arabic_alphabet_shapes/joining).

#### 示例：UTF-8 中的阿拉伯语和英语文本

假设我们创建一个 UTF-8 文本文件，里面包含一行英语和阿拉伯语文本：This is العَرَبِيَّة text!

这一行文本包含 3 个空格字符、11 个英语（拉丁文字系统）字符和 12 个阿拉伯字符（尽管这可能并不立刻明显/显而易见）。当它被保存为 UTF-8 文本文件时，占用了 38 字节的存储空间，原因如下：

* **拉丁文字系统**：空格加英语文本：14 × 1 字节字符 = 14 字节；
* **阿拉伯文字系统**：12 个阿拉伯字符 × 每个字符 2 字节 = 24 字节。

总计 14 + 24 = 38 字节。

#### 深入探究

如果我们将示例文本保存为一个名为 `arabic.txt` 的 UTF-8 文件，并在十六进制编辑器中打开它，就可以检查其包含的实际字节。通过对下面带注释截图的分析，你可以看到阿拉伯文本是按每个字符 2 字节存储的：

![一个在十六进制编辑器中打开的、包含英语和阿拉伯语文本的 UTF-8 文本文件。](/files/e1dfd4ffacf610707e69a711f38deeb228d44eea)

一个在十六进制编辑器中打开的、包含英语和阿拉伯语文本的 UTF-8 文本文件。你可以清楚地看到，拉丁文字系统字符只需要一个字节，而阿拉伯文字系统字符则按每个字符 2 字节存储。

你可以从这张截图中得出几点观察：

* 阿拉伯文本按从左到右的顺序存储，并且这些字符是阿拉伯字母和元音的原始、未整形（孤立）版本；
* 在拉丁文字系统“This is ”之后没有任何额外信息来告知读取该文件的任何软件，下一个字符是阿拉伯文字系统中的字符。

如果你正在排版一个多语言文档（例如同时包含英语和阿拉伯语），那么在读取/处理输入文本文件（作为字节流）时，XeTeX 或 LuaTeX 必须能够检测每个字符的起始和结束，并读取正确数量的字节，以便反向执行 UTF-8 转换并生成相应的 Unicode 码位。正是 UTF-8 算法本身使软件能够做到这一点：它能检测每个单独字符的第一个字节，以及需要读取多少个字节才能计算出相应的 Unicode 码位。UTF-8 很简单易用，但实际上相当巧妙。

#### 逻辑顺序、显示顺序与 OpenType 整形

如果你仔细看上面那段阿拉伯文（العَرَبِيَّة），可能很难看出我们的文本文件确实包含 12 个单独的阿拉伯字符——尤其当你不熟悉阿拉伯文字系统时更是如此！不过，如果你仔细数一数上面截图右侧显示的阿拉伯字符，就会发现总共有 12 个。

对于阿拉伯语这类复杂文字系统语言，我们文本文件 *存储* 中的内容与 *你在屏幕上看到的内容* 在视觉上 *非常* 确实大不相同！当你在浏览器之类的地方查看那段文本时，你看到的是（取决于所用字体）：

![排版后的阿拉伯文本图像](/files/23d8f417c80c4245ec045ebdd33eca4bda09bb91)

但正如上面的截图所示，UTF-8 文本文件实际包含的是这个：

![未排版的阿拉伯文本图像（孤立字符）](/files/e41ba6ccdad2af1b5bc4e44fb68a76654a3cab5c)

即使你不熟悉阿拉伯文字系统的连笔特性，你也能清楚地看出，在将文本文件中的阿拉伯字符传输到排版和/或屏幕显示的过程中（作为字形），“某些东西”发生了变化。如果你习惯于将 TeX/LaTeX 与简单文字系统语言（例如基于拉丁字母的语言）一起使用，这确实会非常令人困惑！

这里有一些重要概念在起作用，因为 Unicode 文本文件负责存储……嗯，文本（Unicode），而排版和显示系统负责使用字体和字形（OpenType）：

* 文本文件按从左到右的顺序保存了阿拉伯字符，但阿拉伯语是从右向左阅读/显示的：文本文件以所谓的 *逻辑顺序*;
* 存储文本。

#### 这是怎么回事？

在文本文件中，阿拉伯语以从左到右的孤立形式字符序列存储：如果你仔细想想，文本文件按顺序/序列存储阿拉伯文本，即 *书写时的顺序* （该 *逻辑顺序*）。只有当这些文本被处理用于显示，或进行排版时，它才会按正确的阅读顺序显示，这通常称为 *视觉顺序* 或 *显示顺序*；此外，阿拉伯字符的孤立形式会被 *整形* 成其排版上正确的显示版本。可以这样理解：一个简单文本文件必须以最基本的形式存储文本（Unicode 字符）：原始、未整形的单个文本字符——系统软件的任务，是根据显示设备上可用的操作系统、字体和排版/渲染软件，将这些字符渲染出来以供显示。

阿拉伯文本在该文件中被排版/显示时，会经历一个称为 *整形*。单个阿拉伯字符会转换为整形后的字形，这些字形能够根据阿拉伯文字系统和书写系统的连写规则，正确表示每个字符所需的变体。此外，高质量的排版软件（使用优质的 OpenType 字体）还会通过一个称为 *OpenType 整形*——一种涵盖广泛排版操作的过程，其中可能包括：

* 将多个单独的字形替换为一个复杂的连字字形（在阿拉伯语中非常常见），或
* 定位操作，例如根据阿拉伯语元音位于哪个字形的上方或下方来调整其位置。

![显示阿拉伯文本在排版时所经历变换的图像](/files/341391e50ff41ef80be382d73ac82aa16748a732)

逻辑顺序与视觉（显示）顺序之间的区别。在这张图中，你可以看到存储在文本文件中的阿拉伯字符在显示或排版时会经过重新排序和字形整形。

高级 OpenType 字体的设计者和创作者投入了大量时间和专业知识，以提供其字体中内置的复杂排版能力。

要关闭应用于阿拉伯文本的字形整形，我们可以使用优秀且免费的， [BabelPad](http://www.babelstone.co.uk/Software/BabelPad.html) Unicode 文本编辑器（仅限 Windows），它允许你禁用字形整形，以查看文本文件中实际存在的原始、独立、未连接（未整形）字符——请参见这张合成截图的下半部分：

![显示 BabelPad 文本编辑器关闭 OpenType 字形整形能力的图像](/files/d38b23c1c7cb223c6acace2fe8ea119d9ae9d21e)

使用 BabelPad Unicode 文本编辑器开启 OpenType 字形整形（上图）或将其关闭（下图）。关闭 OpenType 字形整形会使编辑阿拉伯文本容易得多。

逻辑顺序和显示顺序的概念，加上字形整形过程，在你第一次在编辑或排版包含阿拉伯语等复杂文字的多语言文本文件时遇到它们，可能会相当令人困惑：希望以上内容有助于避免一些初始困惑。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/zh-cn/shen-ru-wen-zhang/51-unicode-utf-8-and-multilingual-text-an-introduction.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
