UTF-16是固定宽度还是可变宽度?为什么UTF-8没有字节顺序问题?


16
  1. UTF-16是固定宽度还是可变宽度?我从不同的来源得到了不同的结果:

    http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF

    UTF-16将Unicode字符存储在16位块中。

    http://en.wikipedia.org/wiki/UTF-16/UCS-2

    UTF-16(16位Unicode转换格式)是Unicode字符编码,能够在Unicode代码空间中从0到0x10FFFF编码1,112,064 [1]个数字(称为代码点)。它产生每个代码点一个或两个16位代码单元的可变长度结果。

  2. 从第一个来源

    UTF-8还具有编码单位为字节的优点,因此不存在字节顺序问题。

    为什么UTF-8没有字节顺序问题?它是可变宽度的,一个字符可能包含一个以上的字节,所以我认为字节顺序仍然会是一个问题吗?

谢谢并恭祝安康!


Answers:


13

(1)字节序列是什么意思,C中的一个char位?UTF-16是字节序列,还是什么?(2)为什么字节序列与可变长度无关?

您似乎在误解什么是字节序问题。这是一个简短的摘要。

一个32位整数占用4个字节。现在,我们知道了这些字节的逻辑顺序。如果您使用的是32位整数,则可以使用以下代码获取其高字节:

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

一切都很好。问题开始的地方是各种硬件如何存储和从内存中检索整数。

按照Big Endian顺序,将读取您作为32位整数读取的4字节内存,第一个字节为高字节:

[0][1][2][3]

按照Little Endian的顺序,将读取您作为32位整数读取的4字节内存,第一个字节为字节:

[3][2][1][0]

如果您有一个指向32位值的指针,则可以执行以下操作:

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

根据C / C ++,其结果是不确定的。可能是0x81。也可以是0x32。从技术上讲,它可以返回任何内容,但对于实际系统,它将返回一个或另一个。

如果您有指向内存地址的指针,则可以将该地址读取为32位值,16位值或8位值。在大字节序的机器上,指针指向高字节。在一点字节序的机器上,指针指向低字节。

请注意,这全部是关于对内存的读写。它与内部C / C ++代码无关。代码的第一个版本,即C / C ++未声明为未定义的版本,将始终可以获取高字节。

问题是当您开始读取字节流时。如来自文件。

16位值与32位值存在相同的问题;它们只有2个字节而不是4个字节。因此,文件可以包含以大端或小端顺序存储的16位值。

UTF-16被定义为16位值的序列。实际上,它是一个uint16_t[]。每个单独的代码单元都是一个16位值。因此,为了正确加载UTF-16,您必须知道数据的字节顺序。

UTF-8定义为8位值的序列。这是一个uint8_t[]。每个单独的代码单元的大小为8位:一个字节。

现在,UTF-16和UTF-8都允许多个代码单元(16位或8位值)组合在一起以形成Unicode代码点(“字符”,但这不是正确的术语;这是一种简化) )。的顺序形成一个码点这些代码单元是由UTF-16和UTF-8编码的决定。

在处理UTF-16时,您将读取16位值,进行任何需要的字节序转换。然后,您检测它是否是一个代理对。如果是,那么您将读取另一个16位值,将两者结合起来,然后从中获得Unicode代码点值。

处理UTF-8时,读取的是8位值。由于只有一个字节,因此无法进行字节序转换。如果第一个字节表示多字节序列,那么您将读取多字节序列中规定的一些字节。每个单独的字节都是一个字节,因此没有字节序转换。该顺序的这些字节的序列中,就如同代理对在UTF-16的顺序,由UTF-8定义。

因此,UTF-8不会有字节序问题。


10

杰里米·班克斯(Jeremy Banks)的回答就目前而言是正确的,但没有解决字节顺序问题。

当您使用UTF-16时,大多数字形都使用两个字节的字存储-但是当该字存储在磁盘文件中时,使用什么顺序存储组成字节?

例如,单词“ water”的CJK(中文)字形的UTF-16编码为6C34的十六进制。当您将其作为两个字节写入磁盘时,是否将其写入“ big-endian”(两个字节为6C 34)?还是将其写为“ little-endian”(两个字节为34 6C)?

使用UTF-16,这两种排序都是合法的,并且通常通过将文件中的第一个单词设为字节序标记(BOM)来指示文件具有哪个字节,对于大尾数编码为FE FF,对于小尾数编码为编码为FF FE。

UTF-32具有相同的问题和相同的解决方案。

UTF-8不会出现此问题,因为它的长度是可变的,因此您可以有效地编写字形的字节序列,就好像它是小尾数一样。例如,字母“ P”始终使用一个字节-80编码,而替换字符始终使用两个字节FF FD顺序编码。

某些程序在UTF-8文件的开头放置了一个三字节的指示器(EF BB BF),这有助于将UTF-8与类似的编码(如ASCII)区分开来,但这在MS Windows上并不常见。


谢谢!(1)字母“ P”只是UTF-8中的一个字节。为什么将替换字符添加到其代码中?(2)在UTF-8中,还有其他字符在UTF-8中具有多个字节。为什么每个这样的字符在字节之间的字节顺序都不成问题?
StackExchange for All

@Tim:(1)您没有在P的代码中添加替换字符。如果看到80 FF FD,则为两个字符-一个P字符和一个替换字符。
鲍勃·墨菲

(2)始终以FF FD的顺序写入和读取“替换字符”的两个字节。如果您还可以将“替换字符”编写为FD FF,则只会出现字节顺序问题,但是您不能这样做。两个字节的序列将不是“替换字符”。
Bob Murphy

1
@Tim:您可能想通过en.wikipedia.org/wiki/UTF-8进行工作。它确实非常好,如果您能理解所有内容以及其他与Unicode相关的Wikipedia页面,我想您会发现自己对此没有更多疑问。
Bob Murphy

4
UTF-8字节顺序没有问题的原因是,编码被定义为字节序列,并且没有不同字节序的变化。它与可变长度无关。
starblue 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.