最近我在处理字符编码时遇到了一个问题,当我深入研究字符集和字符编码时,我产生了这个疑问。UTF-8编码是最流行的编码之一,因为它与ASCII向后兼容。由于UTF-8是可变长度编码格式,它如何区分单字节和双字节字符。例如,"Aݔ" 存储为 "410754"(A的Unicode为41,阿拉伯字符的Unicode为0754)。编码如何确定41是一个字符,而0754是另一个双字节字符?为什么不将它视为一个双字节字符4107和一个单字节字符54呢?
最近我在处理字符编码时遇到了一个问题,当我深入研究字符集和字符编码时,我产生了这个疑问。UTF-8编码是最流行的编码之一,因为它与ASCII向后兼容。由于UTF-8是可变长度编码格式,它如何区分单字节和双字节字符。例如,"Aݔ" 存储为 "410754"(A的Unicode为41,阿拉伯字符的Unicode为0754)。编码如何确定41是一个字符,而0754是另一个双字节字符?为什么不将它视为一个双字节字符4107和一个单字节字符54呢?
0x41
,即二进制中的01000001
。
所有其他字符都用多个字节表示。U+0080到U+07FF每个使用两个字节,U+0800到U+FFFF每个使用三个字节,U+10000到U+10FFFF每个使用四个字节。
计算机可以知道一个字符在哪里结束,下一个字符从哪里开始,因为UTF-8是这样设计的,使得用于ASCII的单字节值不重叠于多字节序列中使用的值。字节0x00
到0x7F
仅用于ASCII,而以上的字节仅用于多字节序列。此外,在多字节序列开头使用的字节也不能出现在序列的任何其他位置。
因此需要对代码点进行编码。请考虑以下二进制模式:
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
10
开头。要对字符进行编码,请将其代码点转换为二进制,并填写x的位置。例如:U+0754位于U+0080和U+07FF之间,因此需要两个字节。0x0754
的二进制形式为11101010100
,因此您将x替换为这些数字:
11011101 10010100
简短回答:
UTF-8旨在能够明确地识别文本流中每个字节的类型:
你的例子 Aݔ
由Unicode代码点U+0041和U+0754组成,它在UTF-8中的编码为:
01000001 11011101 10010100
因此,在解码时,UTF-8知道第一个字节必须是一个1字节代码,第二个字节必须是2字节代码的前导字节,第三个字节必须是一个连续字节,由于第二个字节是2字节代码的前导字节,所以第二个和第三个字节必须组成这个2字节代码。
请参见此处了解UTF-8如何编码Unicode代码点。
需要澄清的是,ASCII意味着标准的7位ASCII,而不是欧洲常用的扩展8位ASCII。
因此,第一个字节的一部分(0x80到0xFF)采用双字节表示,第二个字节的一部分(0x0800到0xFFFF)采用完整的三字节表示。
四字节表示仅使用最低的三个字节,并且仅使用了16,777,215中的1,114,111种可能性。
你可以在这里找到xls 链接。
这意味着解释器必须在发现这些二进制模式时“跳回”NUL(0)字节。
希望这能帮助有人!
var byteCount = Encoding.UTF8.GetByteCount(new char[] {ch});
- Eric J.