提问人:sarsnake 提问时间:3/14/2009 最后编辑:trentsarsnake 更新时间:11/1/2023 访问量:388066
UTF-8 和 Unicode 有什么区别?
What is the difference between UTF-8 and Unicode?
答:
它们不是一回事 - UTF-8 是一种特殊的 Unicode 编码方式。
您可以根据应用程序和要使用的数据选择许多不同的编码。据我所知,最常见的是 UTF-8、UTF-16 和 UTF-32。
评论
不幸的是,“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的一些参考资料:
- Unicode 联盟网站,特别是教程部分
- 乔尔的文章
- 我自己的文章(。面向 NET)
评论
Unicode 仅定义码位,即表示字符的数字。如何在内存中存储这些代码点取决于所使用的编码。UTF-8 是编码 Unicode 字符的一种方式。
评论
Unicode 只是一个标准,它定义了字符集 (UCS) 和编码 (UTF) 以对此字符集进行编码。但一般来说,Unicode 指的是字符集而不是标准。
阅读每个软件开发人员绝对、肯定地必须在 5 分钟内了解 Unicode 和字符集(没有任何借口!)和 Unicode。
评论
为了扩展其他人给出的答案:
我们有很多语言,有很多字符,计算机应该理想地显示这些字符。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 中处理多单位字符。
希望能填补一些细节。
评论
0x04000000
0x7FFFFFFF
1111110v 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv
我已经检查了 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 ?..."
评论
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)
评论
http://www.wikiwand.com/en/UTF-8#/Description
现有的答案已经解释了很多细节,但这里有一个非常简短的答案,有最直接的解释和例子。
Unicode 是将字符映射到代码点的标准。
每个字符都有一个唯一的代码点(标识号),这是一个类似于 9731 的数字。
UTF-8 是代码点的编码。
为了将所有字符存储在磁盘上(在文件中),UTF-8 将字符拆分为最多 4 个八位字节(8 位序列)字节。
UTF-8 是几种编码(表示数据的方法)之一。例如,在 Unicode 中,(十进制)代码点 9731 表示一个雪人 (),它由 3 个字节组成,采用 UTF-8 格式:☃
E2 98 83
这是一个带有一些随机示例的排序列表。
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是我们在计算机中保存的“$”值。
评论
让我用一个例子来说明这个主题:
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 中学习本主题,请单击此处。
评论
0
110
10
1110
10
UTF-8 是 Unicode 文本的编码方案。在许多上下文中,尤其是 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 个字节,也不需要知道我们从字符串中开始读取的距离。
评论
它们是一回事,不是吗?
不,他们不是。
我认为您引用的维基百科页面的第一句话给出了一个很好的简短总结:
UTF-8 是一种可变宽度字符编码,能够使用 1 到 4 个 8 位字节对 Unicode 中的所有 1,112,064 个有效码位进行编码。
详细阐述:
Unicode 是一种标准,它定义了从字符到数字的映射,即所谓的代码点(如下例所示)。如需完整映射,您可以查看此处。
! -> U+0021 (21), " -> U+0022 (22), \# -> U+0023 (23)
UTF-8 是以计算机可以理解的形式(也称为位)对这些代码点进行编码的方法之一。换句话说,它是一种将每个码位转换为位序列或将位序列转换为等效码位的方法/算法。请注意,Unicode 有很多替代编码。
乔尔在这里给出了一个非常好的解释和历史概述。
UTF-8 是一种使用 8 位序列对 Unicode 字符进行编码的方法。
Unicode 是表示来自多种语言的各种字符的标准。
评论
01000001
11010011 10000101
11100101 10100011 10000110
11110001 10110001 10000010 10110001
0
110
1110
11110
如果我可以总结一下我从这个线程中收集到的内容:
Unicode 将字符分配给序数(十进制形式)。(这些数字称为代码点。
à -> 224
UTF-8 是一种将这些序数(十进制形式)“翻译”为二进制表示形式的编码。
224 -> 11000011 10100000
请注意,我们谈论的是 224 的二进制表示形式,而不是它的二进制形式,即 0b11100000。
本文介绍了所有详细信息 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.
评论
一个简单的答案,直截了当:
- Unicode 是表示来自许多人类语言的字符的标准。
- UTF-8 是一种对 Unicode 字符进行编码的方法。
* 我故意忽略了 UTF-8 的内部工作原理。
评论
所以你最终通常来自谷歌,并想尝试不同的东西。
但是,如何打印和转换所有这些字符集呢?
在这里,我列出了一些有用的单行字。
在 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 发行版上以不同的方式命名)。iconv
hexdump
xxd
libiconv
util-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
在阅读了有关此主题的大量帖子和文章后,我的解释:
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)
上表中的“x”字符表示“免费”的数量 位“,这些位是空的,我们可以写给它们。
其他位保留用于 UTF-8 格式,它们用作 标题/标记。多亏了这些标头,当字节被 使用 UTF-8 编码读取,计算机知道要读取哪些字节 一起和分开。
使用 UTF-8 格式编码后字符的字节大小, 取决于您需要写入多少位。
在我们的例子中,“汉”字符正好是 2 个字节或 16 位:
"01101100 01001001"
因此,我们的字符被编码为 UTF-8 后的大小将是 3 个字节或 24 位
"11100110 10110001 10001001"
因为“3 UTF-8 字节”有 16 个可用位,我们可以写入
- 解决方案,分步如下:
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 位。
评论
汉
01101100 01001001
00100111 01100100
00100111 01100100
11100010 10011101 10100100
评论
0
110
1110
11110
10