关于编码:UTF-8和Unicode有什么区别

What is the difference between UTF-8 and Unicode

根据维基百科的utf-8页面,我听到了人们的不同意见。

它们是一样的,不是吗?有人能解释清楚吗?


扩展其他人给出的答案:

我们有许多语言,其中有许多字符,计算机应该理想地显示出来。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中,4个在UTF-32中),但其他语言字符可以占六个字节或更多。

多字节编码(在上面的解释之后我应该说是多单元编码)的优点是它们相对节省空间,但缺点是,诸如查找子字符串、比较等操作在执行这些操作之前都必须将字符解码为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中的多单元字符。

希望能填上一些细节。


不幸的是,根据上下文,"unicode"以各种不同的方式使用。它最正确的用途(IMO)是作为一个编码字符集——即一组字符以及字符和表示它们的整数代码点之间的映射。

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

当"unicode"用作字符编码的名称(例如.NET encoding.unicode属性)时,它通常表示utf-16,它将最常见的字符编码为两个字节。一些平台(特别是.NET和Java)使用UTF 16作为它们的"原生"字符编码。如果您需要担心不能用单个UTF-16值编码的字符(它们被编码为"代理项对"),这会导致很多问题,但是大多数开发人员从不担心这个,IME。

Unicode上的一些引用:

  • Unicode联合体网站,尤其是教程部分
  • 乔尔的文章
  • 我自己的文章(面向网络)


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

1
2
3
A chinese character:      汉
it's unicode value:       U+6C49
convert 6C49 to binary:   01101100 01001001

到目前为止没有什么神奇的,很简单。现在,假设我们决定将这个角色存储在硬盘上。为此,我们需要以二进制格式存储字符。我们可以简单地将其存储为"011100 01001001"。完成!

不过,等一下,"011100001001001"是一个字符还是两个字符?你知道这是一个字符,因为我告诉过你,但当一台计算机读到它时,它不知道。所以我们需要某种"编码"来告诉计算机把它当作一个整体来对待。

这就是"utf-8"规则的来源:http://www.fileformat.info/info/unicode/utf8.htm

1
2
3
4
5
6
7
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"格式存储这个字符,我们需要在字符前面加一些"headers"。我们的中文字符长16位(自己计算二进制值),因此我们将使用第3行的格式,因为它提供了足够的空间:

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

将结果写出一行:

1
11100110 10110001 10001001

这是汉字的utf-8(二进制)值!(自己确认:http://www.fileformat.info/info/unicode/char/6c49/index.htm)

总结

1
2
3
4
A chinese character:      汉
it's unicode value:       U+6C49
convert 6C49 to binary:   01101100 01001001
embed 6C49 as UTF-8:      11100110 10110001 10001001


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

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


Unicode只定义代码点,即表示字符的数字。如何在内存中存储这些代码点取决于所使用的编码。UTF-8是编码Unicode字符的一种方法,还有许多其他方法。


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

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

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

例如,

ucs字符=unicode汉字

UCS码位=U+24B62

UTF-8编码=F0 A4 AD A2(十六进制)=11110000 1010100100 1010101 101000110(bin)


Unicode只是一个定义字符集(UCS)和编码(UTF)来编码该字符集的标准。但一般来说,Unicode指的是字符集而不是标准。

阅读绝对最低限度每个软件开发人员绝对,肯定必须知道Unicode和字符集(没有借口!)和Unicode在5分钟内。


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

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

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

这是一个有随机例子的排序列表。


1。统一码

世界上有很多字符,比如"$,&;,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是我们在计算机中为"$"保存的值。


我已经检查了gumbo答案中的链接,我想在这里粘贴一些内容,以便在堆栈溢出时也存在。

"…有些人错误地认为Unicode只是一个16位代码,每个字符占16位,因此可能有65536个字符。事实上,这不是正确的。这是关于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编码的最早想法是,嘿,让我们把这些数字分别存储在两个字节中。所以你好变成了

00 48 00 65 00 6c 00 6c 00 6f

正确的?不要这么快!难道它也不是:

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


Unicode是一个宽泛范围的标准,它定义了超过130000个字符,并为每个字符分配一个数字代码("代码点")。它还定义了如何对文本排序、使其正常化、更改大小写等等的规则。Unicode中的字符由0到0x10ffff(包括0到0x10ffff)的代码点表示,但某些代码点是保留的,不能用于字符。

Unicode中的代码可以用多个编码表示。最简单的是utf-32,它简单地将代码点编码为32位整数,每个整数的宽度为4字节。

UTF-8是另一种编码方式,并很快成为事实上的标准。它编码为一个字节值序列。每个代码点可以使用这些字节的可变数目。ASCII范围内的代码点是裸编码的,以便与ASCII兼容。超出此范围的代码点使用的字节数可变,可以是2、3或4,具体取决于它们所处的范围。

UTF-8的设计考虑了这些特性:

  • ASCII字符的编码与它们在ASCII中的编码完全相同,这样一个ASCII字符串作为UTF-8也是有效的。

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

  • ASCII范围之外的字符不使用ASCII范围内的任何字节,确保它们不会被误认为是ASCII字符。这也是一个安全功能。

  • UTF-8可以很容易地被验证,并且可以通过验证器与其他字符编码区分开。其他8位或多字节编码中的文本也很少验证为UTF-8。

  • 随机访问:在UTF-8字符串的任何一点上,都可以判断该位置的字节是否是字符的第一个字节,并且可以回溯到该字符的开头,而不需要引用字符串开头的任何内容。


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

Unicode是表示多种语言中多种字符的标准。


They are the same thing, aren't they?

不,他们没有。

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

UTF-8 is a variable width character encoding capable of encoding all 1,112,064 valid code points in Unicode using one to four 8-bit bytes.

详述:

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

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

乔尔给出了一个非常好的解释和历史概况。