469

What's the basis for Unicode and why the need for UTF-8 or UTF-16? I have researched this on Google and searched here as well, but it's not clear to me.

In VSS, when doing a file comparison, sometimes there is a message saying the two files have differing UTF's. Why would this be the case?

Please explain in simple terms.

4

9 回答 9

637

为什么我们需要Unicode?

在(不太)早期,所有存在的都是ASCII。这没关系,因为只需要几个控制字符、标点符号、数字和字母,就像这句话中的一样。不幸的是,没有预见到当今全球互通和社交媒体的奇怪世界,在同一份文件中看到英语、العربية、汉语、עִבְרִית、ελληνικά和ភាសាខ្មែរ 并不少见(希望我没有破坏任何旧的浏览器)。

但为了争论,假设 Joe Average 是一名软件开发人员。他坚持认为他永远只需要英语,因此只想使用 ASCII。这对于用户Joe 来说可能很好,但对于软件开发人员Joe 来说就不好了。世界上大约有一半的人使用非拉丁字符,而使用 ASCII 对这些人来说可能是不体谅的,最重要的是,他正在关闭他的软件,以适应一个庞大且不断增长的经济体。

因此,需要一个包含所有语言的包容性字符集。于是出现了Unicode。它为每个字符分配一个唯一编号,称为代码点。与其他可能的集合相比,Unicode 的一个优点是前 256 个代码点与ISO-8859-1相同,因此也与 ASCII 相同。此外,绝大多数常用字符在称为基本多语言平面 (BMP)的区域中只能用两个字节表示。现在需要一个字符编码来访问这个字符集,正如问题所要求的那样,我将专注于 UTF-8 和 UTF-16。

内存注意事项

那么有多少字节可以访问这些编码中的哪些字符呢?

  • UTF-8:
  • 1 个字节:标准 ASCII
  • 2 个字节:阿拉伯语、希伯来语、大多数欧洲文字(最显着的不包括格鲁吉亚语
  • 3 个字节:BMP
  • 4 个字节:所有 Unicode 字符
  • UTF-16:
  • 2个字节:BMP
  • 4 个字节:所有 Unicode 字符

现在值得一提的是,不在 BMP 中的字符包括古文字、数学符号、音乐符号,以及更稀有的中文、日文和韩文 (CJK)字符。

如果您主要使用 ASCII 字符,那么 UTF-8 肯定会更节省内存。但是,如果您主要使用非欧洲脚本,则使用 UTF-8 的内存效率可能比 UTF-16 低 1.5 倍。在处理大量文本时,例如大型网页或冗长的 word 文档,这可能会影响性能。

编码基础

注意:如果您知道 UTF-8 和 UTF-16 是如何编码的,请跳到下一节进行实际应用。

  • UTF-8:对于标准 ASCII (0-127) 字符,UTF-8 代码是相同的。如果需要与现有 ASCII 文本向后兼容,这使得 UTF-8 成为理想的选择。其他字符需要 2-4 个字节。这是通过在每个字节中保留一些位来指示它是多字节字符的一部分来完成的。特别是,每个字节的第一位是1为了避免与 ASCII 字符发生冲突。
  • UTF-16:对于有效的 BMP 字符,UTF-16 表示只是它的代码点。但是,对于非 BMP 字符,UTF-16 引入了代理对。在这种情况下,两个两字节部分的组合映射到一个非 BMP 字符。这些两字节部分来自 BMP 数字范围,但 Unicode 标准保证作为 BMP 字符无效。此外,由于 UTF-16 以两个字节为基本单位,因此受到字节序的影响。作为补偿,可以在数据流的开头放置一个保留的字节顺序标记,以指示字节顺序。因此,如果您正在读取 UTF-16 输入,并且未指定字节顺序,则必须检查这一点。

可以看出,UTF-8 和 UTF-16 几乎无法相互兼容。因此,如果您正在执行 I/O,请确保您知道您使用的是哪种编码!有关这些编码的更多详细信息,请参阅UTF FAQ

实际编程注意事项

字符和字符串数据类型:它们是如何在编程语言中编码的?如果它们是原始字节,那么在您尝试输出非 ASCII 字符的那一刻,您可能会遇到一些问题。此外,即使字符类型基于 UTF,也不意味着字符串是正确的 UTF。它们可能允许非法的字节序列。通常,您必须使用支持 UTF 的库,例如用于 C、C++ 和 Java的ICU 。在任何情况下,如果您想输入/输出默认编码以外的其他内容,则必须先对其进行转换。

Recommended, default, and dominant encodings: When given a choice of which UTF to use, it is usually best to follow recommended standards for the environment you are working in. For example, UTF-8 is dominant on the web, and since HTML5,它一直是推荐的编码。相反,.NETJava环境都基于 UTF-16 字符类型。令人困惑(并且错误地),经常提到“Unicode 编码”,它通常是指在给定环境中占主导地位的 UTF 编码。

库支持:您使用的库支持某种编码。哪一个?他们支持极端案例吗?由于必要性是发明之母,UTF-8 库通常会正确支​​持 4 字节字符,因为 1、2 甚至 3 字节字符可能会频繁出现。但是,并非所有声称的 UTF-16 库都正确支持代理对,因为它们很少出现。

计数字符: Unicode 中存在组合字符。例如,代码点 U+006E (n) 和 U+0303(组合波浪号)形成 ñ,但代码点 U+00F1 形成 ñ。它们看起来应该相同,但是一个简单的计数算法将在第一个示例中返回 2,而在后一个示例中返回 1。这不一定是错误的,但也可能不是预期的结果。

比较相等性: A、А 和 Α 看起来相同,但它们分别是拉丁文、西里尔文和希腊文。你也有像 C 和 Ⅽ 这样的情况。一个是字母,另一个是罗马数字。此外,我们还需要考虑组合字符。有关详细信息,请参阅Unicode 中的重复字符

代理对:这些在 Stack Overflow 上经常出现,所以我只提供一些示例链接:

于 2013-02-28T05:24:15.060 回答
92
于 2015-01-06T07:45:59.947 回答
33

Unicode 是一个相当复杂的标准。不要太害怕,但要为一些工作做好准备![2]

因为总是需要一个可信的资源,但官方的报告是海量的,我建议阅读以下内容:

  1. 每个软件开发人员绝对、肯定地必须了解 Unicode 和字符集的绝对最低要求(没有任何借口!) Stack Exchange 首席执行官 Joel Spolsky 的介绍。
  2. 到 BMP 及以后!Eric Muller 的教程,当时的技术总监,后来的副总裁,在 Unicode 联盟(前 20 张幻灯片,你就完成了)

简要说明:

计算机读取字节,人们读取字符,所以我们使用编码标准将字符映射到字节。ASCII 是第一个广泛使用的标准,但仅涵盖拉丁语(7 位/字符可以表示 128 个不同的字符)。Unicode 是一个标准,其目标是涵盖世界上所有可能的字符(最多可以容纳 1,114,112 个字符,这意味着最多 21 位/字符。当前的 Unicode 8.0 总共指定了 120,737 个字符,仅此而已)。

主要区别在于 ASCII 字符可以容纳一个字节(八位),但大多数 Unicode 字符不能。因此使用了编码形式/方案(如 UTF-8 和 UTF-16),字符模型如下所示:

每个字符都有一个从 0 到 1,114,111(十六进制:0-10FFFF)的枚举位置,称为代码点编码形式
将代码点映射到代码单元序列。代码单元是您希望字符在内存中组织的方式、8 位单元、16 位单元等。UTF-8 使用一到四个 8 位单元,而 UTF-16 使用一到两个 16 位单元,以覆盖最大 21 位的整个 Unicode。单位使用前缀以便可以发现字符边界,更多的单位意味着更多的前缀占用位。因此,尽管 UTF-8 为拉丁文脚本使用一个字节,但它需要三个字节用于Basic Multilingual Plane中的后续脚本,而 UTF-16 对所有这些都使用两个字节。这就是他们的主要区别。
最后,编码方案(如 UTF-16BE 或 UTF-16LE)将代码单元序列映射(序列化)为字节序列。

字符:π
代码点:U+03C0
编码形式(代码单元):
      UTF-8:CF 80
      UTF-16:03C0
编码方案(字节):
      UTF-8:CF 80
      UTF-16BE:03 C0
      UTF-16LE:C0 03

提示:一个十六进制数字代表四位,所以一个两位十六进制数字代表一个字节。
还可以查看Wikipedia 上的平面地图以了解字符集布局。

于 2015-10-27T01:03:19.977 回答
28
于 2017-01-17T22:41:24.240 回答
21

最初,Unicode 旨在具有固定宽度的 16 位编码 ( UCS-2 )。Unicode 的早期采用者,如 Java 和 Windows NT,围绕 16 位字符串构建了他们的库。

后来,Unicode 的范围扩大到包括历史字符,这需要超过 16 位编码支持的 65,536 个代码点。为了允许在使用 UCS-2 的平台上表示附加字符,引入了 UTF-16 编码。它使用“代理对”来表示补充平面中的字符。

同时,许多较旧的软件和网络协议都使用 8 位字符串。UTF-8 是为了让这些系统可以支持 Unicode 而不必使用宽字符。它向后兼容 7 位 ASCII。

于 2010-07-05T05:04:27.450 回答
12

Unicode是一种将所有语言中的字符映射到称为代码点的特定数值的标准。这样做的原因是它允许使用相同的代码点集进行不同的编码。

UTF-8 和 UTF-16 就是这样的两种编码。它们将代码点作为输入,并使用一些定义明确的公式对它们进行编码以生成编码字符串。

选择特定的编码取决于您的要求。不同的编码具有不同的内存要求,并且根据您要处理的字符,您应该选择使用最少字节序列来编码这些字符的编码。

有关 Unicode、UTF-8 和 UTF-16 的更多详细信息,您可以查看这篇文章,

每个程序员都应该了解 Unicode

于 2017-03-25T15:10:57.683 回答
9

为什么是统一码?因为 ASCII 只有 127 个字符。从 128 到 255 的那些在不同的国家/地区有所不同,这就是为什么会有代码页。所以他们说:让我们最多有 1114111 个字符。

那么如何存储最高代码点呢?您需要使用 21 位存储它,因此您将使用具有 32 位的 DWORD,而浪费了 11 位。因此,如果您使用 DWORD 来存储 Unicode 字符,这是最简单的方法,因为您的 DWORD 中的值与代码点完全匹配。

但是 DWORD 数组当然比 WORD 数组大,当然甚至比 BYTE 数组还要大。这就是为什么不仅有 UTF-32,还有 UTF-16 的原因。但是 UTF-16 表示一个 WORD 流,而一个 WORD 有 16 位,那么最高码点 1114111 怎么能适合一个 WORD 呢?这不可以!

因此,他们将高于 65535 的所有内容放入一个 DWORD 中,他们称之为代理对。这样的代理对是两个 WORDS,可以通过查看前 6 位来检测。

那么UTF-8呢?它是一个字节数组或字节流,但是最高码点 1114111 怎么能适合一个字节呢?这不可以!好的,所以他们也输入了一个 DWORD 对吗?或者可能是一个词,对吧?几乎正确!

他们发明了 utf-8 序列,这意味着每个高于 127 的代码点都必须编码为 2 字节、3 字节或 4 字节序列。哇!但是我们怎样才能检测到这样的序列呢?嗯,最多 127 的所有内容都是 ASCII 并且是单个字节。110开头的是两字节序列,1110开头的是三字节序列,11110开头的是四字节序列。这些所谓的“起始字节”的剩余位属于代码点。

现在根据顺序,后面的字节必须跟随。后面的字节以 10 开头,其余位为 6 位有效载荷位,属于代码点。连接起始字节的有效负载位和以下字节/秒,您将获得代码点。这就是 UTF-8 的全部魅力。

于 2014-01-15T14:02:13.603 回答
5

ASCII - 软件仅在内存中为给定字符分配 8 位字节。它适用于英语和采用(外来词,如façade)字符,因为它们对应的十进制值低于十进制值 128。示例 C 程序。

UTF-8 - 软件为给定字符分配一到四个可变的 8 位字节。这里的变量是什么意思?假设您通过浏览器中的 HTML 页面发送字符“A”(HTML 为 UTF-8),A 对应的十进制值为 65,当您将其转换为十进制时,它变为 01000010。这只需要一个字节, 甚至为单词façade中的 'ç' 等特殊采用的英文字符分配一个字节的内存。但是,当您要存储欧洲字符时,它需要两个字节,因此您需要 UTF-8。但是,当您使用亚洲字符时,您需要最少两个字节,最多四个字节。同样,表情符号需要三到四个字节。UTF-8 将解决您的所有需求。

UTF-16 将为每个字符分配最少 2 个字节和最多 4 个字节,它不会分配 1 或 3 个字节。每个字符用 16 位或 32 位表示。

那为什么 UTF-16 会存在呢?最初,Unicode 是 16 位而不是 8 位。Java 采用了原始版本的 UTF-16。

简而言之,除非您正在使用的语言或平台已经采用了 UTF-16,否则您在任何地方都不需要 UTF-16。

Web 浏览器调用的 Java 程序使用 UTF-16,但 Web 浏览器使用 UTF-8 发送字符。

于 2018-12-06T08:41:39.100 回答
2

UTF 代表Unicode 转换格式。基本上,在当今世界,存在用数百种其他语言编写的脚本,这些格式未被早期使用的基本 ASCII 涵盖。因此,UTF 应运而生。

UTF-8 具有字符编码能力,其代码单元为 8 位,而 UTF-16 为 16 位。

于 2016-08-30T09:39:34.777 回答