UTF-8 和 Unicode 有什么区别?

What is the difference between UTF-8 and Unicode?

提问人:sarsnake 提问时间:3/14/2009 最后编辑:trentsarsnake 更新时间:11/1/2023 访问量:388066

问:

我从人们那里听到了相互矛盾的意见 - 根据维基百科 UTF-8 页面。

它们是一回事,不是吗?有人可以澄清一下吗?

Unicode UTF-8 字符编码 术语

评论

1赞 brighty 6/26/2014
在我看来,这个 WIKI 写的关于 unicode 和 UTF 的内容是可以的。关于它的一些评论很奇怪:“在 UTF-8(或任何其他多字节编码)中,可以在字符中间拆分或截断字符串,这可能会导致字符串无效。因此,采用 UTF-8 编码的字符串不再是字符串,而是字节数组或字节流。组成字符串的字符被编码。当然,它也可以被解码。现在,当然,您可以在开始字节之后或后续字节之后剪切 utf-8 序列,但为什么要有人这样做呢?
1赞 Everett 7/13/2019
这篇关于字符串数据类型的文章很有教育意义: mortoray.com/2013/11/27/the-string-type-is-broken -- 有时在处理字符串及其字节级组件时,您可能会无意中将一个字符切成两半。
0赞 SlySven 9/18/2021
@brighty 如果该字节流通过分组的网络传输,则字符串可能会被拆分为两个数据包 - 即在 UTF-8 边界以外的位置(即下一个字节不是 MSBits 为 、 、 或 )...011011101111010
0赞 brighty 9/19/2021
@SlySven 你说的是字节流还是字符串?当然,一个字节流可以拆分为两个数据包,但TCP的工作是在目的地重新创建难题,例如,每个数据包都有其序列号,并且接收方确实确认收到的每个数据包。当然,如果 TCP/IP 会话不正常地断开连接,则只有部分(比如 utf-8 编码的字节流)到达目的地。
0赞 SlySven 9/21/2021
双!我主要为 MUD 客户端应用程序编写代码,在没有额外的(所谓的“Go-Ahead”或“End-of-record”)信令的情况下,数据包在穿越 Internet 时可以而且确实会被拆分 - 如果客户端没有等待足够长的时间等待任何进一步的数据包......

答:

130赞 Greg 3/14/2009 #1

它们不是一回事 - UTF-8 是一种特殊的 Unicode 编码方式。

您可以根据应用程序和要使用的数据选择许多不同的编码。据我所知,最常见的是 UTF-8、UTF-16 和 UTF-32。

评论

14赞 serhio 7/27/2010
但是,关键是一些编辑器建议将文件保存为“Unicode”或“UTF-8”。因此,在这种情况下,提到“Unicode”是UTF-16,我认为是必要的。
247赞 Jon Skeet 3/14/2009 #2

不幸的是,“Unicode”以各种不同的方式使用,具体取决于上下文。它最正确的用途 (IMO) 是作为编码字符 - 即一组字符以及字符和表示它们的整数码位之间的映射。

UTF-8 是一种字符编码 - 一种从字节序列转换为字符序列的方法,反之亦然。它涵盖了整个 Unicode 字符集。ASCII 编码为每个字符一个字节,其他字符根据其确切的码位占用更多字节(所有当前定义的码位最多 4 个字节,即最多 U-0010FFFF,实际上 4 个字节可以处理高达 U-001FFFFF)。

当“Unicode”用作字符编码的名称(例如,作为 .NET Encoding.Unicode 属性)时,它通常表示 UTF-16,它将最常见的字符编码为两个字节。某些平台(特别是 .NET 和 Java)使用 UTF-16 作为其“本机”字符编码。如果您需要担心无法在单个 UTF-16 值中编码的字符(它们被编码为“代理对”),这会导致毛茸茸的问题 - 但大多数开发人员从不担心这一点,IME。

关于Unicode的一些参考资料:

评论

21赞 jalf 3/14/2009
我认为 UTF-16 只等于 Windows 平台上的“Unicode”。人们倾向于在 *nix 上默认使用 UTF-8。+1 虽然,好答案
10赞 Jon Skeet 3/14/2009
@Chris:不,ISO-8859-1 不是 UTF-8。UTF-8 将 U+0080 到 U+00FF 编码为两个字节,而不是一个字节。Windows 1252 和 ISO-8859-1 基本相同,但如果我没记错的话,它们在值 0x80 和 0x99 值之间有所不同,其中 ISO 8859-1 有一个“孔”,但 CP1252 定义了字符。
13赞 thomasrutter 3/14/2009
将 UTF-16 称为“Unicode”的想法让我感到不安,因为它可能会造成混淆 - 尽管这被明确指出只是 .NET 约定。UTF-16 是一种表示 Unicode 的方式,但它不是“Unicode 编码”。
7赞 Jon Skeet 3/14/2009
@unwesen:UTF-8 不需要代理项对。它只是使用逐渐变长的字节序列表示非 BMP 字符。
5赞 Jon Skeet 4/28/2013
@RoyiNamir:是的,不幸的是,“Unicode”经常被用来表示“UTF-16”,尤其是在 Windows 中。
105赞 Martin Cote 3/14/2009 #3

Unicode 仅定义码位,即表示字符的数字。如何在内存中存储这些代码点取决于所使用的编码。UTF-8 是编码 Unicode 字符的一种方式。

评论

3赞 serhio 7/27/2010
但是,关键是一些编辑器建议将文件保存为“Unicode”或“UTF-8”。因此,在这种情况下,提到“Unicode”是UTF-16,我认为是必要的。
0赞 brighty 6/26/2014
表示字符的数字也执行 ASCII。
26赞 Gumbo 3/14/2009 #4

Unicode 只是一个标准,它定义了字符集 (UCS) 和编码 (UTF) 以对此字符集进行编码。但一般来说,Unicode 指的是字符集而不是标准。

阅读每个软件开发人员绝对、肯定地必须在 5 分钟内了解 Unicode 和字符集(没有任何借口!)和 Unicode

评论

1赞 Gumbo 7/27/2010
@serhio:我知道。尽管有三种不同的 UTF-16 编码:两种显式 UTF-16LE 和 UTF-16BE 以及隐式 UTF-16,其中字节序是用 BOM 指定的。
0赞 Mooing Duck 3/25/2015
@Gumbo:缺少 BOM 并不意味着它是一种不同的编码。只有两种编码。
639赞 unwesen 3/14/2009 #5

为了扩展其他人给出的答案:

我们有很多语言,有很多字符,计算机应该理想地显示这些字符。Unicode 为每个字符分配一个唯一的编号或码位。

计算机处理诸如字节之类的数字......这里跳过一些历史并忽略内存寻址问题,8 位计算机会将 8 位字节视为硬件上容易表示的最大数字单位,16 位计算机会将其扩展到两个字节,依此类推。

像 ASCII 这样的旧字符编码来自(前)8 位时代,并试图将当时计算中的主要语言(即英语)塞进 0 到 127(7 位)的数字中。字母表中有 26 个字母,包括大写和非大写形式、数字和标点符号,效果很好。对于其他非英语语言,ASCII 扩展了第 8 位,但此扩展提供的额外 128 个数字/码位将根据显示的语言映射到不同的字符。ISO-8859 标准是这种映射的最常见形式;ISO-8859-1 和 ISO-8859-15(也称为 ISO-Latin-1、latin1,是的,8859 ISO 标准也有两个不同的版本)。

但是,当您想要表示来自多种语言的字符时,这还不够,因此将所有可用字符塞入单个字节是行不通的。

基本上有两种不同类型的编码:一种通过添加更多位来扩展值范围。这些编码的示例包括 UCS2(2 字节 = 16 位)和 UCS4(4 字节 = 32 位)。它们本质上存在与 ASCII 和 ISO-8859 标准相同的问题,因为它们的值范围仍然有限,即使限制要高得多。

另一种类型的编码使用每个字符的可变字节数,最常见的编码是 UTF 编码。所有 UTF 编码的工作方式大致相同:您选择一个单元大小,UTF-8 为 8 位,UTF-16 为 16 位,UTF-32 为 32 位。然后,该标准将其中一些位定义为标志:如果设置了它们,则单元序列中的下一个单元将被视为同一字符的一部分。如果未设置它们,则此单位完全表示一个字符。因此,最常见的(英语)字符在 UTF-8 中仅占用一个字节(在 UTF-16 中为 2 个字节,在 UTF-32 中为 4 个字节),但其他语言字符可以占用 6 个字节或更多。

多字节编码(在上面的解释之后,我应该说多单元)的优点是它们相对节省空间,但缺点是查找子字符串、比较等操作都必须将字符解码为 Unicode 码位才能执行此类操作(尽管有一些快捷方式)。

UCS标准和UTF标准都按照Unicode中的定义对码位进行编码。从理论上讲,这些编码可用于对任何数字进行编码(在编码支持的范围内)——当然,这些编码是为了对 Unicode 码位进行编码。这就是你们之间的关系。

Windows 将所谓的“Unicode”字符串处理为 UTF-16 字符串,而现在大多数 UNIX 默认为 UTF-8。HTTP等通信协议往往最适合UTF-8,因为UTF-8中的单位大小与ASCII中的单位大小相同,并且大多数此类协议都是在ASCII时代设计的。另一方面,UTF-16 在表示所有现存语言时提供了最佳的平均空间/处理性能。

Unicode 标准定义的码位少于可以用 32 位表示的码位。因此,出于所有实际目的,UTF-32 和 UCS4 变成了相同的编码,因为您不太可能在 UTF-32 中处理多单位字符。

希望能填补一些细节。

评论

13赞 Mechanical snail 8/24/2011
从概念上讲,UCS-2 和 UCS-4 是字符,而不是字符编码(因此得名)。
92赞 tchrist 8/26/2011
@Tuukka 此帖子中的错误很多。ISO 8859 不止 2 个版本。ASCII 不适用于英语,缺少大引号、分号、重音等内容——Unicode 不仅仅是非英语;英语也需要它!在任何编码中,任何代码点都不能占用超过 4 个字节;这个 6 字节的业务是完全错误的。你不能对任何Unicode标量值进行UTF编码,因为这说:代理项和其他66个非字符都是被禁止的。UCS-4 和 UTF-32 是不一样的。没有多单元 UTF-32。UTF-16 并不像他们假装的那么有效——&c&c&c!
2赞 TRiG 1/18/2012
ASCII 也不包含英镑符号 £,当然也不包含欧元符号 €(它比 ASCII 年轻得多)。
3赞 syntaxerror 9/27/2014
@tchrist 看起来 6 个字节毕竟不是不可能。看这个:joelonsoftware.com/articles/Unicode.html 表示有一个字符空间 from to ,或者在二进制中它是 - 这确实是 6 个字节。但是,最大值为 6 个字节,而不是像文章令人困惑地声称“六个字节或更多”那样。0x040000000x7FFFFFFF1111110v 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv
15赞 Mooing Duck 3/25/2015
@syntaxerror:“只有代码点 128 及以上使用 2、3 存储,实际上最多 6 个字节”在编写时是准确的,但同年晚些时候(十二年前)它被无效了。en.wikipedia.org/wiki/UTF-8 说:“原始规范涵盖最多 31 位的数字(通用字符集的原始限制)。2003 年 11 月,RFC 3629 将 UTF-8 限制为 U+10FFFF,以匹配 UTF-16 字符编码的约束。这删除了所有 5 字节和 6 字节的序列,以及大约一半的 4 字节序列。
12赞 kommradHomer 5/30/2011 #6

我已经检查了 Gumbo 答案中的链接,我想将其中的一部分粘贴到这里以存在于 Stack Overflow 上。

"...有些人误以为Unicode只是一个16位代码,每个字符需要16位,因此有65,536个可能的字符。实际上,这是不正确的。这是关于Unicode最常见的一个神话,所以如果你这么想,不要感到难过。

事实上,Unicode对字符有不同的思考方式,你必须了解Unicode对事物的思考方式,否则就没有意义了。

到目前为止,我们假设一个字母映射到一些可以存储在磁盘或内存中的位:

A -> 0100 0001

在Unicode中,一个字母映射到一个叫做代码点的东西,它仍然只是一个理论概念。该代码点在内存或磁盘上的表示方式是另一回事......”

"...每个字母表中的每个柏拉图字母都由Unicode联盟分配一个幻数,其写法如下:U+0639。这个幻数称为代码点。U+ 表示“Unicode”,数字为十六进制。U+0639 是阿拉伯字母 Ain。英文字母 A 是 U+0041......”

"...好的,假设我们有一个字符串:

你好

在 Unicode 中,它对应于以下五个代码点:

U+0048、U+0065、U+006C、U+006C、U+006F。

只是一堆代码点。数字,真的。我们还没有说过如何将其存储在内存中或在电子邮件中表示它......”

"...这就是编码的用武之地。

Unicode编码的最早想法,导致了关于两个字节的神话,嘿,让我们把这些数字存储在每个字节中。所以 Hello 变成了

00 48 00 65 00 6C 00 6C 00 6F

右?没那么快!难道不能也是:

48 00 65 00 6C 00 6C 00 6F 00 ?..."

评论

0赞 brighty 6/26/2014
在 ASCII 中,字母也映射到代码点,而不仅仅是在 unicode 中。
42赞 nightlytrails 2/25/2013 #7

Unicode 是一种标准,它与 ISO/IEC 10646 一起定义了通用字符集 (UCS),它是表示几乎所有已知语言所需的所有现有字符的超集。

Unicode 为其库中的每个字符分配一个名称和一个数字(字符代码或代码点)。

UTF-8 编码是一种在计算机内存中以数字方式表示这些字符的方法。UTF-8 将每个代码点映射到八位字节(8 位字节)序列中

例如,

UCS 字符 = Unicode 韩字符

UCS 码位 = U+24B62

UTF-8 编码 = F0 A4 AD A2(十六进制)= 11110000 10100100 10101101 10100010(bin)

评论

0赞 brighty 6/26/2014
不可以,UTF-8 仅将代码点映射到大于 127 的序列中。从 0 到 127 的所有内容都不是一个序列,而是一个字节。顺便说一句,ASCII 还将字符的名称分配给数字,因此这与 Unicode 的作用相同。但 Unicode 不会止步于代码点 127,而是上升到 0x10ffff。
2赞 nightlytrails 6/26/2014
@brightly我不同意。Ascii 字符确实映射到单个字节序列。第一位(在 ascii 字符的代码中为 0)表示后面有多少字节 - 零。 请看第一行。http://www.wikiwand.com/en/UTF-8#/Description
0赞 brighty 6/28/2014
好吧,对我来说,一个序列由多个字节组成。UTF-8 中的 ASCII 字符按原样为单个字节,最高有效位设置为 0。然后,高于 127 的代码点需要序列,这些序列始终具有一个起始字节和一个、两个或三个后续字节。那么,为什么要将单个字节称为“序列”呢?
0赞 nightlytrails 6/28/2014
井。。。很多时候,英语律师可能会对它在软件中的故意滥用感到困惑。这里的情况也一样。你可以为此争论。但这不会让它更清楚。
2赞 chux - Reinstate Monica 2/13/2017
@brighty 嗯,在数学中,0 元素的序列是可以的。这里 1 个元素的序列也可以。
25赞 basic6 5/19/2014 #8

现有的答案已经解释了很多细节,但这里有一个非常简短的答案,有最直接的解释和例子。

Unicode 是将字符映射到代码点的标准
每个字符都有一个唯一的代码点(标识号),这是一个类似于 9731 的数字。

UTF-8 是代码点编码
为了将所有字符存储在磁盘上(在文件中),UTF-8 将字符拆分为最多 4 个八位字节(8 位序列)字节。 UTF-8 是几种编码(表示数据的方法)之一。例如,在 Unicode 中,(十进制)代码点 9731 表示一个雪人 (),它由 3 个字节组成,采用 UTF-8 格式:
E2 98 83

这是一个带有一些随机示例的排序列表

19赞 wengeezhang 1/5/2015 #9

1. Unicode的

世界上有很多字符,比如“$,&,h,a,t,?,张,1,=,+...”。

然后出现了一个致力于这些角色的组织,

他们制定了一个名为“Unicode”的标准。

标准如下:

  • 创建一个表单,其中每个位置称为“码位”或“码位”。
  • 整个位置从 U+0000 到 U+10FFFF;
  • 到目前为止,有些位置是用字符填充的,而其他位置是保存或空的。
  • 例如,位置“U+0024”用字符“$”填充。

PS:当然,还有另一个叫做ISO的组织在维护另一个标准--“ISO 10646”,几乎是一样的。

2. UTF-8 格式

如上所述,U+0024 只是一个位置,因此我们不能将“U+0024”保存在计算机中以获取字符“$”。

必须有编码方法。

然后是编码方法,如UTF-8,UTF-16,UTF-32,UCS-2。

在 UTF-8 下,代码点“U+0024”被编码为00100100。

00100100是我们在计算机中保存的“$”值。

评论

2赞 Rick James 8/20/2016
一般来说,UTF-8 是当今任何人使用的唯一变体。
3赞 thomasrutter 9/26/2017
ISO 10646 是与 Unicode 字符集相同的标准。Unicode 定义了字符集以外的许多内容,例如排序规则、大小写等.ISO 10646 只是字符集(目前有超过 130,000 个字符集)。Unicode 联盟和 ISO 共同开发 Unicode,ISO 只关注字符集及其编码,Unicode 还定义字符属性和处理文本的规则。
458赞 Cheng 1/14/2015 #10

让我用一个例子来说明这个主题:

A Chinese character:      汉
its Unicode value:        U+6C49
convert 6C49 to binary:   01101100 01001001

到目前为止没有什么神奇的,很简单。现在,假设我们决定将此字符存储在我们的硬盘上。为此,我们需要以二进制格式存储字符。我们可以简单地将其按原样存储为“01101100 01001001”。做!

但是等一下,“01101100 01001001”是一个字符还是两个字符?你知道这是一个字符,因为我告诉过你,但是当计算机读取它时,它不知道。因此,我们需要某种编码来告诉计算机将其视为一个编码。

这就是 UTF-8 规则的用武之地:https://www.fileformat.info/info/unicode/utf8.htm

Binary format of bytes in sequence

1st Byte    2nd Byte    3rd Byte    4th Byte    Number of Free Bits   Maximum Expressible Unicode Value
0xxxxxxx                                                7             007F hex (127)
110xxxxx    10xxxxxx                                (5+6)=11          07FF hex (2047)
1110xxxx    10xxxxxx    10xxxxxx                  (4+6+6)=16          FFFF hex (65535)
11110xxx    10xxxxxx    10xxxxxx    10xxxxxx    (3+6+6+6)=21          10FFFF hex (1,114,111)

根据上表,如果我们想使用 UTF-8 格式存储这个字符,我们需要在字符前面加上一些“标头”。我们的汉字长度为 16 位(自己计算二进制值),因此我们将使用上面第 3 行的格式,因为它提供了足够的空间:

Header  Place holder    Fill in our Binary   Result         
1110    xxxx            0110                 11100110
10      xxxxxx          110001               10110001
10      xxxxxx          001001               10001001

用一行写出结果:

11100110 10110001 10001001

这是汉字的UTF-8二进制值!亲眼看看:https://www.fileformat.info/info/unicode/char/6c49/index.htm

总结

A Chinese character:      汉
its Unicode value:        U+6C49
convert 6C49 to binary:   01101100 01001001
encode 6C49 as UTF-8:     11100110 10110001 10001001

P.S. 如果您想在 Python 中学习本主题,请单击此处

评论

8赞 Koray Tugay 5/22/2015
“但是等一下,'01101100 01001001'是一个角色还是两个角色?你知道这是一个字符,因为我告诉过你,但是当计算机读取它时,它不知道。因此,我们需要某种“编码”来告诉计算机将其视为一个。好吧,但是计算机仍然不知道它应该用 utf-8 对其进行编码?
40赞 Cheng 5/22/2015
@KorayTugay 计算机不知道应该使用什么编码。当您将字符保存到文件时以及从文件中读取字符时,您必须告诉它。
6赞 Cheng 4/18/2016
@Connor 计算机不知道使用什么格式。保存文档时,文本编辑器必须将其编码显式设置为 utf-8 或用户想要使用的任何格式。此外,当文本编辑器程序读取文件时,它需要选择文本编码方案才能正确解码。当您输入和输入字母时也是如此,文本编辑器需要知道您使用的方案,以便正确保存它。
3赞 JBoy 8/15/2016
那么这些标题是如何解释的呢?如果我看第一个表,那么我认为:如果字节以 bit 开头,则字符由 1 bite(当前位)表示,如果字节以 开头,则字符由 2 个字节表示(当前和下一个字节(后面的剩余位)),如果字节以 开头,则字符由 3 个字节表示, 当前和接下来的 2 个字节(后面的剩余位)。011010111010
31赞 jrhee17 3/11/2018
阅读 10 篇关于 UTF-8 的文章;看完这篇文章后,我在 10 秒内就明白了:)
32赞 thomasrutter 9/26/2017 #11

UTF-8Unicode 文本的编码方案。在许多上下文中,尤其是 Web,它正在成为 Unicode 文本最受支持和最知名的文本编码,并且是 JSON 和 XML 中默认使用的文本编码。

Unicode 是一个范围广泛的标准,它定义了超过 149,000 个字符,并为每个字符分配了一个数字代码(一个码位)。它还定义了如何对文本进行排序、规范化、更改大小写等的规则。Unicode 中的字符由从零到0x10FFFF(含)的码位表示,但有些码位是保留的,不能用于字符。

有多种方法可以将 Unicode 码位字符串编码为二进制流。这些称为“编码”。最直接的编码是 UTF-32,它只是将每个码位存储为 32 位整数,每个码位宽 4 个字节。由于代码点最多只能达到 0x10FFFF 位(需要 21 位),因此这种编码有些浪费。

UTF-8 是另一种编码,由于许多优点,它比其他编码更受欢迎。UTF-8 将每个码位编码为 1、2、3 或 4 字节值的序列。ASCII 范围内的码位编码为单个字节值,使其与 ASCII 完全兼容。超出此范围的代码点分别使用 2、3 或 4 个字节,具体取决于它们所处的范围。

UTF-8 在设计时考虑了以下属性:

  • ASCII 编码中也存在的字符的编码方式与 ASCII 中的编码方式完全相同,因此任何 ASCII 字符串自然也是表示相同字符的有效 UTF-8 字符串。

  • 效率更高:UTF-8 格式的文本字符串几乎总是比 UTF-32 或 UTF-16 中的相同字符串占用更少的空间,只有少数例外。

  • 二进制排序:使用二进制排序对 UTF-8 字符串进行排序仍会导致所有代码点按数字顺序排序。

  • 当代码点使用多个字节时,这些字节(甚至第一个字节)都不包含 ASCII 范围内的值,从而确保它们的任何部分都不会被误认为是 ASCII 字符。这是一项对安全性非常重要的功能,尤其是在最初为 8 位编码设计的系统中使用 UTF-8 编码文本时。

  • 可以很容易地验证 UTF-8 以验证它是否是有效的 UTF-8。由于 UTF-8 的结构非常特殊,其他 8 位或多字节编码中的文本很少会偶然验证为 UTF-8。

  • 随机访问:在 UTF-8 字符串中的任何一点,都可以判断该位置的字节是否是字符的第一个字节,并找到下一个或当前字符的开头,而无需向前或向后扫描超过 3 个字节,也不需要知道我们从字符串中开始读取的距离。

评论

0赞 skomisa 12/21/2019
几个小问题:[1] “ASCII 字符的编码与 ASCII 中的编码完全相同”不应该更改为“ASCII 字符的编码与 UTF-8 中的编码完全相同”吗?[2] “Unicode中的代码......”这句话(对我来说)是不清楚的。你的意思是“Unicode码位......”吗?
0赞 thomasrutter 12/23/2019
@skomisa第 1 点,我的意思是 ASCII 范围内的字符编码对于 ASCII 和 UTF-8 是相同的。
0赞 thomasrutter 12/23/2019
对于第 2 点,这是一个公平的观点,我将对其进行编辑以使其更清晰
0赞 tripleee 11/1/2023
回复:您最近的编辑,tonsky.me/blog/unicode 引用了 170,000 个分配的代码点。
1赞 thomasrutter 11/1/2023
@tripleee我认为这归结为代码点和字符之间的区别——您的图可能包括用于私人使用或代理编码等的码点,而我的图只是字符。我的来源是 unicode.org FAQ,截至 Unicode 15 是正确的
5赞 Dimos 1/12/2018 #12

它们是一回事,不是吗?

不,他们不是。


我认为您引用的维基百科页面的第一句话给出了一个很好的简短总结:

UTF-8 是一种可变宽度字符编码,能够使用 1 到 4 个 8 位字节对 Unicode 中的所有 1,112,064 个有效码位进行编码。

详细阐述:

  • Unicode 是一种标准,它定义了从字符到数字的映射,即所谓的代码点(如下例所示)。如需完整映射,您可以查看此处

    ! -> U+0021 (21),  
    " -> U+0022 (22),  
    \# -> U+0023 (23)
    
  • UTF-8 是以计算机可以理解的形式(也称为位)对这些代码点进行编码的方法之一换句话说,它是一种将每个码位转换为位序列或将位序列转换为等效码位的方法/算法。请注意,Unicode 有很多替代编码。


乔尔在这里给出了一个非常好的解释和历史概述

3赞 akaMahesh 1/26/2018 #13

UTF-8 是一种使用 8 位序列对 Unicode 字符进行编码的方法。

Unicode 是表示来自多种语言的各种字符的标准。

评论

5赞 deceze 1/26/2018
“8 位序列”......?可能想更准确地指定...
0赞 Jin Lim 2/19/2022
“8 位序列”的意思是,它可以呈现 8 位格式。像这些,,或或。正如你所看到的,当涉及到UTF-8时,它可以是最小1个字节,最大4个字节。0100000111010011 1000010111100101 10100011 1000011011110001 10110001 10000010 10110001
0赞 Jin Lim 2/19/2022
请注意,当您要使用 1 个字节时,第一个数字是 。当您要使用 2byte 时,前 3 位数字是 .当您要使用 3 个字节时,前 4 位数字是 。当您要使用 4 个字节时,前 5 位数字是 。哼。你明白了吗?:)0110111011110
15赞 remykarem 7/18/2019 #14

如果我可以总结一下我从这个线程中收集到的内容:

Unicode 将字符分配给序数(十进制形式)。(这些数字称为代码点。

à -> 224

UTF-8 是一种将这些序数(十进制形式)“翻译”为二进制表示形式的编码。

224 -> 11000011 10100000

请注意,我们谈论的是 224 的二进制表示形式,而不是它的二进制形式,即 0b11100000。

16赞 InGeek 10/12/2019 #15

本文介绍了所有详细信息 http://kunststube.net/encoding/

写入缓冲区

如果写入 4 字节缓冲区,则使用 UTF8 编码的符号,则二进制文件将如下所示:

00000000 11100011 10000001 10000010

如果写入 4 字节缓冲区,则使用 UTF16 编码的符号,则二进制文件将如下所示:

00000000 00000000 00110000 01000010

正如你所看到的,根据你在内容中使用的语言,这将相应地影响你的记忆。

例如,对于这个特定的符号:UTF16 编码更有效,因为我们有 2 个备用字节用于下一个符号。但这并不意味着您必须使用 UTF16 作为日本字母。

从缓冲区读取

现在,如果你想读取上面的字节,你必须知道它是用什么编码写的,并正确地解码回来。

例如,如果您将此 : 00000000 11100011 10000001 10000010解码为 UTF16 编码,您最终将得到

注意:编码和 Unicode 是两回事。Unicode 是一个大(表),每个符号都映射到一个唯一的码位。例如: 符号(字母)有一个(码位):30 42(十六进制)。另一方面,编码是一种在存储到硬件时将符号转换为更合适的方式的算法。

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.

在此处输入图像描述

评论

0赞 berimbolo 12/10/2021
对于 UTF-8 中的汉字,为什么保存为 3 个字节而不是 2 个字节,格式与 UTF-16 相同?
0赞 cristian9804 7/13/2023
最后,一篇好文章
2赞 Luis Lavaire 11/11/2021 #16

一个简单的答案,直截了当:

  • Unicode 是表示来自许多人类语言的字符的标准。
  • UTF-8 是一种对 Unicode 字符进行编码的方法。

* 我故意忽略了 UTF-8 的内部工作原理。

评论

0赞 Joe 6/1/2023
这确实回答了 Unicode 与 UTF-8 的概念及其角色的问题。
1赞 not2qubit 1/4/2022 #17

所以你最终通常来自谷歌,并想尝试不同的东西。
但是,如何打印和转换所有这些字符集呢?

在这里,我列出了一些有用的单行字。

Powershell 中:

# Print character with the Unicode point (U+<hexcode>) using this: 
[char]0x2550

# With Python installed, you can print the unicode character from U+xxxx with:
python -c 'print(u"\u2585")'

如果您有更多 Powershell trix 或快捷方式,请发表评论。

Bash 中,您会喜欢 和 和 包(可能在其他 *nix 发行版上以不同的方式命名)。iconvhexdumpxxdlibiconvutil-linux

# To print the 3-byte hex code for a Unicode character:
printf "\\\x%s" $(printf '═'|xxd -p -c1 -u)
#\xE2\x95\x90

# To print the Unicode character represented by hex string:
printf '\xE2\x96\x85'
#▅

# To convert from UTF-16LE to Unicode
echo -en "════"| iconv -f UTF-16LE -t UNICODEFFFE

# To convert a string into hex: 
echo -en '═�'| xxd -g 1
#00000000: e2 95 90 ef bf bd

# To convert a string into binary:
echo -en '═�\n'| xxd -b
#00000000: 11100010 10010101 10010000 11101111 10111111 10111101  ......
#00000006: 00001010

# To convert a binary string into hex:
printf  '%x\n' "$((2#111000111000000110000010))"
#e38182

19赞 nightboy 1/15/2022 #18

在阅读了有关此主题的大量帖子和文章后,我的解释:

1 - Unicode 字符百科

“Unicode”是一个巨大的表,宽 21 位,这些 21 位为 1,114,112 个码位/值/字段/存储字符的位置提供了空间。

在这 1,114,112 个码位中,有 1,111,998 个能够存储 Unicode 字符,因为有 2048 个码位保留为代理项,66 个码位保留为非字符。因此,有 1,111,998 个代码点可以存储唯一的字符、符号、表情符号等。

但是,截至目前,这 1,114,112 个代码点中只有 144,697 个被使用。这 144,697 个代码点包含涵盖所有语言的字符,以及符号、表情符号等。

“Unicode”中的每个字符都被分配给一个特定的码位,也就是一个特定的值/Unicode编号。例如,字符“❤”仅使用 1,114,112 个码位中的一个码位。它的值(又名Unicode编号)为“U+2764”。这是一个由两个字节组成的十六进制码位,在二进制中表示为00100111 01100100。但是为了表示这个码位,UTF-8 编码使用 3 个字节(24 位),在二进制中表示为 11100010 10011101 10100100(没有两个空格字符,每个字符都使用 1 位,我添加它们只是为了视觉目的,以使 24 位更具可读性,所以请忽略它们)。

现在,我们的计算机应该如何知道这 3 个字节“11100010 10011101 10100100”是单独读取还是一起读取?如果将这 3 个字节分开读取,然后转换为字符,结果将是“Ô, Ø, ñ”,这与我们的心形表情符号“❤”相比有很大的不同。

2 - 编码标准(UTF-8、ISO-8859、Windows-1251 等)

为了解决这个问题,人们发明了编码标准。 自 2008 年以来,最受欢迎的是 UTF-8。UTF-8 平均占所有网页的 97.6%,这就是为什么我们将 UTF-8 用于下面的示例。

2.1 - 什么是编码?

编码,简单地说就是将某物从一件事转换为另一件事。在我们的例子中,我们正在将数据,更具体地说是字节转换为 UTF-8 格式,我还想将这句话改写为:“将字节转换为 UTF-8 字节”,尽管它在技术上可能不正确。

2.2 关于 UTF-8 格式的一些信息,以及为什么它如此重要

UTF-8 使用最少 1 个字节来存储一个字符,最多使用 4 个字节。由于 UTF-8 格式,我们可以拥有超过 1 个字节信息的字符。

这非常重要,因为如果不是 UTF-8 格式,我们将无法拥有如此丰富的字母,因为某些字母的字母无法容纳 1 个字节,我们也不会有表情符号,因为每个表情符号至少需要 3 个字节。我很确定你现在已经明白了,所以让我们继续前进。

2.3 将汉字编码为UTF-8的示例

现在,假设我们有汉字“汉”。

这个字符正好需要 16 个二进制位“01101100 01001001”,因此正如我们上面所讨论的,除非我们将其编码为 UTF-8,否则我们无法读取此字符,因为计算机将无法知道这 2 个字节是单独读取还是一起读取。

将这个“汉”字符的 2 个字节转换为我喜欢称之为 UTF-8 字节,将产生以下结果:

(正常字节)“01101100 01001001” ->(UTF-8 编码字节)“11100110 10110001 10001001”

现在,我们是如何得到 3 个字节而不是 2 个字节的?这应该是 UTF-8 编码,将 2 个字节变成 3 个字节?

为了解释 UTF-8 编码的工作原理,我将从字面上复制 @MatthiasBraun 的回复,对他的出色解释表示感谢。

2.4 UTF-8 编码是如何工作的?

我们这里有的是将字节编码为 UTF-8 的模板。这就是编码的发生方式,如果你问我,非常令人兴奋!

现在,仔细看看下面的表格,然后我们将一起浏览它。

        Binary format of bytes in sequence:

        1st Byte    2nd Byte    3rd Byte    4th Byte    Number of Free Bits   Maximum Expressible Unicode Value
        0xxxxxxx                                                7             007F hex (127)
        110xxxxx    10xxxxxx                                (5+6)=11          07FF hex (2047)
        1110xxxx    10xxxxxx    10xxxxxx                  (4+6+6)=16          FFFF hex (65535)
        11110xxx    10xxxxxx    10xxxxxx    10xxxxxx    (3+6+6+6)=21          10FFFF hex (1,114,111)
  1. 上表中的“x”字符表示“免费”的数量 位“,这些位是空的,我们可以写给它们。

  2. 其他位保留用于 UTF-8 格式,它们用作 标题/标记。多亏了这些标头,当字节被 使用 UTF-8 编码读取,计算机知道要读取哪些字节 一起和分开。

  3. 使用 UTF-8 格式编码后字符的字节大小, 取决于您需要写入多少位。

  • 在我们的例子中,“汉”字符正好是 2 个字节或 16 位:

  • "01101100 01001001"

  • 因此,我们的字符被编码为 UTF-8 后的大小将是 3 个字节或 24 位

  • "11100110 10110001 10001001"

  • 因为“3 UTF-8 字节”有 16 个可用位,我们可以写入

  1. 解决方案,分步如下:

2.5 解决方案:

        Header  Place holder    Fill in our Binary   Result         
        1110    xxxx            0110                 11100110
        10      xxxxxx          110001               10110001
        10      xxxxxx          001001               10001001 

2.6 总结:

        A Chinese character:      汉
        its Unicode value:        U+6C49
        convert 6C49 to binary:   01101100 01001001
        encode 6C49 as UTF-8:     11100110 10110001 10001001

3 - UTF-8、UTF-16 和 UTF-32 之间的区别

UTF-8、UTF-16 和 UTF-32 编码之间差异的原始解释:https://javarevisited.blogspot.com/2015/02/difference-between-utf-8-utf-16-and-utf.html

UTF-8、UTF-16 和 UTF-32 字符编码之间的主要区别在于它们需要多少字节才能表示内存中的字符:

UTF-8 至少使用 1 个字节,但如果字符较大,则可以使用 2、3 或 4 个字节。UTF-8 也与 ASCII 表兼容。

UTF-16 至少使用 2 个字节。UTF-16 不能占用 3 个字节,它可以占用 2 或 4 个字节。UTF-16 与 ASCII 表不兼容。

UTF-32 始终使用 4 个字节。

请记住:UTF-8 和 UTF-16 是可变长度编码,其中 UTF-8 可以占用 1 到 4 个字节,而 UTF-16 可以占用 2 或 4 个字节。UTF-32 是一种固定宽度的编码,它始终需要 32 位。

评论

0赞 Jin Lim 2/19/2022
你怎么能找到正好是 2 个字节或 16 位:.在 Unicode 中。我能看到表格吗?01101100 01001001
0赞 BenderBoy 6/2/2023
这比它需要的要令人困惑得多。我已经迷路了»值“U+2764”在二进制中看起来像:“11100010 10011101 10100100”«。首先,2764 是十六进制并不明显。其次,在二进制中,它应该是这样的。实际上,这句话应该说»U+2764是由两个字节组成的十六进制代码点。然而,为了表示此代码点,UTF-8 编码使用 3 个字节。下面将解释 UTF-8 如何以及为什么从 to 获取。00100111 0110010000100111 0110010011100010 10011101 10100100