我要做的是让一个int
接受一个UTF-8-16-32字符,这样它应该能够判断它是UTF-8、UTF-16还是UTF-32。
我使用fopen(fp, "rb")
从文本文件中读取二进制值。我遇到了一个问题,一个字符被分成两个字节。
例如,如果我尝试读取字符CENT SIGN
文本文件input.txt
包含:
¢
我得到:
utf code: LATIN CAPITAL LETTER A WITH CIRCUMFLEX
binary: 11000010
hexadecimal: 0xC2
decimal: 194
character: �
utf code: CENT SIGN
binary: 10100010
hexadecimal: 0xA2
decimal: 162
character: �
utf code: LINE FEED (LF)
binary: 00001010
hexadecimal: 0xA
decimal: 10
character:
代码:
int ch;
while ((ch = fgetc(stream)) != EOF) {
printf(“utf code:t”);
findCode(ch); // HERE
write(1, “binary: “, 16);
printBits(ch);
printf(“nhexadecimal:t%X”, ch);
printf(“ndecimal:t%d”, ch);
printf(“ncharacter:t%cnn”, ch);
}
注意:在UTF-8数据库中,CENT SIGN
的二进制值为0xC2A2
或11000010:10100010
问题是fgetc只读取1个字节。
您根本无法检测数据使用的是哪种UTF-what?
编码,因为UTF-???
是UTF字符的编码。
幸运的是,标记数据的编码可以在数据中使用,但这不是强制性的。BOM
几乎是为了这个目的而发布的(请参阅注释),但您会发现许多UTF文档(无论采用何种编码)都没有遵循这种方法。在UTF-8、UTF-16或UTF-32编码中,相同的比特模式意味着不同的东西,因此您必须搜索编码错误来丢弃(可能是全部)无效编码,以猜测正确的编码。
如果文档的开头有一个BOM
标记,那么该字节序列将允许您检测正在进行的编码,因为它的表示会根据实际编码获得不同的模式。
0xef, 0xbb, 0xbf => UTF-8 (no endianness)
0xfe, 0xff => UTF-16-BE (big endian)
0xff, 0xfe => UTF-16-LE (little endian)
0x00, 0x00, 0xfe, 0xff => UTF-32-BE (big endian)
0xff, 0xfe, 0x00, 0x00 => UTF-32-LE (little endian)
但正如你所看到的,UTF-32-LE
和UTF-16-LE
的开头相同,UTF-32-BE
和UTF-16-BE
的开头一样,所以这并不能完全回答你的问题。例如,序列为0xff, 0xfe, 0x00, 0x00
的文件是UTF-32-LE
中没有数据(只有BOM)的完全有效文件,或者是UTF-16-LE
中具有Unicode字符"NULL"U+0000字符的完全有效的文件。
最好的方法是将编码作为参数传递给输入例程,这样它们就可以对数据进行适当的解码。
编辑
在您使用的示例中,传递字符CENT SIGN
(好吧,我假设您的意思是您有字符代码U+00A2
,它以二进制形式表示(完成为UTF代码的21位表示)00000000010100010
。如果你把这个字符编码为UTF-8
,你会得到一个两个字符的编码,比如:0xe2, 0xa2
,当你把它编码为UTF-16-LE
时,你会获得:0xa2, 0x00
,如果你把它编为UTF-16-BE
,你会收到0x00, 0xa2
,如果你编码为UTF-32-LE
,你会接到0xa2, 0x00, 0x00, 0x00
,如果你将它编码为UTF-32-BE
,你会拿到0x00, 0x00, 0x00, 0xa2
。这里的问题是,您使用4字节的序列来表示所有unicode,当编码UTF-32时(以及不同的顺序,取决于您是使用big-endian编码还是使用little-endian编码),当您使用UTF-16编码时(几乎所有的Unicode都低于限制U+10000
,所以当它们不适合16位时,几乎所有的unicode都可以表示为单个UTF-16代码),当使用UTF-8编码时,可以表示为1到4字节的序列。因此,您必须知道的第一件事是,unicodeCODEPOINT与用于表示它的编码不同(这已经有了固定的编码),因此,通过对代码点(整个unicode表中字符的数字顺序)进行测试,您无法知道使用了哪种编码来编码unicode-char
备注
BOM
是Not a character U+fffe
字符的替代用法。当它被放在文档的开头时,它会将其含义切换为表示deByte Order Mark character
,因此这很不幸,因为它会迫使您将其包含两次,以防您想用它开始文档。顺便说一句,根据定义,这个字符不是字符,因此您很少将其视为普通文档字符。当UTF文档中发生某些解码时,它通常用作替换字符。
信用
BOM
表示表来自维基百科页面