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

它们是一样的,不是吗?有人能澄清一下吗?


当前回答

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

Unicode是将字符映射到码点的标准。 每个字符都有一个唯一的编码点(识别号),它是一个像9731这样的数字。

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

这是一个排序的列表,其中有一些随机的例子。

其他回答

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

在5分钟内阅读每个软件开发人员绝对必须知道的关于Unicode和字符集(没有借口!)和Unicode的绝对最小值。

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

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格式存储这个字符,我们需要给我们的字符加上一些'headers'前缀。我们的中文字符有16位长(你自己计算二进制值),所以我们将在第三行使用该格式,因为它提供了足够的空间:

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

附注:如果你想用Python学习本主题,请点击这里。

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

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

UTF-8是Unicode文本的一种可能的编码方案。

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

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

UTF-8是另一种编码,由于与UTF-32和其他编码相比有许多优点,它正在成为事实上的标准。UTF-8将每个码位编码为1、2、3或4个字节值的序列。ASCII范围内的码位被编码为一个单字节值,以便与ASCII兼容。超出这个范围的代码点分别使用2、3或4个字节,这取决于它们所在的范围。

UTF-8在设计时考虑了这些属性:

ASCII characters are encoded exactly as they are in ASCII, such that an ASCII string is also a valid UTF-8 string representing the same characters. More efficient: Text strings in UTF-8 almost always occupy less space than the same strings in either UTF-32 or UTF-16, with just a few exceptions. Binary sorting: Sorting UTF-8 strings using a binary sort will still result in all code points being sorted in numerical order. When a code point uses multiple bytes, none of those bytes contain values in the ASCII range, ensuring that no part of them could be mistaken for an ASCII character. This is also a security feature. UTF-8 can be easily validated, and distinguished from other character encodings by a validator. Text in other 8-bit or multi-byte encodings will very rarely also validate as UTF-8 due to the very specific structure of UTF-8. Random access: At any point in a UTF-8 string it is possible to tell if the byte at that position is the first byte of a character or not, and to find the start of the next or current character, without needing to scan forwards or backwards more than 3 bytes or to know how far into the string we started reading from.

在阅读了大量关于这个话题的帖子和文章后,我的解释是:

1 - Unicode字符表

“Unicode”是一个巨大的表,它有21位宽,这21位提供了1,114,112个码点/值/字段/位置来存储字符。

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

然而,到目前为止,在这1114112个代码点中,只有144697个被使用。 这144,697个代码点包含了涵盖所有语言的字符,以及符号、表情符号等。

Each character in the "Unicode" is assigned to a specific codepoint aka has a specific value / Unicode number. For Example the character "❤", has the following value aka Unicode number "U+2764". The value "U+2764" takes exactly one codepoint out of the 1,114,112 codepoints. The value "U+2764" looks like that in binary: "11100010 10011101 10100100", which is exactly 3 bytes or 24bits (without the two empty space characters, each of which taking 1 bit, but I have added them for visual purposes only, in order to make the 24bits more readable, so please ignore them).

现在,我们的计算机应该如何知道这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字节转换为我喜欢称其为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)

The "x" characters in the table above represent the number of "Free Bits", those bits are empty and we can write to them. The other bits are reserved for the UTF-8 format, they are used as headers / markers. Thanks to these headers, when the bytes are being read using the UTF-8 encoding, the computer knows, which bytes to read together and which seperately. The byte size of your character, after being encoded using the UTF-8 format, depends on how many bits you need to write. In our case the "汉" character is exactly 2 bytes or 16bits: "01101100 01001001" thus the size of our character after being encoded to UTF-8, will be 3 bytes or 24bits "11100110 10110001 10001001" because "3 UTF-8 bytes" have 16 Free Bits, which we can write to Solution, step by step below:

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位。