UTF-8 encoding in C with getchar()
我必须编写一个代码,用UTF-8编码字符并将它们"翻译"成Unicode。您可以在这里查看什么是utf-8 https://en.wikipedia.org/wiki/utf-8。我是C初学者,因此我有三个限制:
我必须使用getchar()。
禁止使用阵列
我只对1、2、3和4字节的Unicode字符感兴趣
所以我有一个完全能用4字节的代码(我知道我必须对每个getchar();使用!= EOF,但现在这不是我的问题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <stdio.h>
int main (void) {
int ch1 , ch2 , ch3 , ch4 , c ;
ch1 = getchar();
ch2 = getchar();
ch3 = getchar();
ch4 = getchar();
if ((ch1 & 0xF8) != 0xF0 || (ch2 & 0xC0) != 0x80 ||
(ch3 & 0xC0) != 0x80 || (ch4 & 0xC0) != 0x80) {
printf("Error in UTF-8 4-byte encoding
");
return 1;
}
c = ((ch1 & 0x07) << 18) | ((ch2 & 0x3F) << 12) |
((ch3 & 0x3F) << 6) | (ch4 & 0x3F);
printf("c = %05X
", c );
return 0;
} |
我的问题是:我不明白如何使用getchar()来处理1-2-3字节。我的意思是,我必须先阅读所有的getchar函数,然后用ch1来表示1字节字符,用ch1和ch2来表示2字节字符,否则我必须这样做。(顺便说一句,下面的代码是不起作用的,它给了我一个无限的循环;我只是用它作为我思想的一个例子。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <stdio.h>
int main (void) {
int ch1 , ch2 , ch3 , ch4 , c ;
if (c >=0x0000 && c <=0x007F ){
ch1 =getchar();
while (ch1 !=EOF ){
if ((ch1 & 0x80) != 0x00) {
printf("Error in UTF-8 1-byte encoding
");
return 1;
}
c = ((ch1 & 0x80) << 7);
printf("c = %05X
", c );
}
} |
- 注意,UTF-8永远不需要超过4个字节,因为Unicode将自身限制在U+0000的范围内。U+10FFFF。实际上,一些字节-0xc0、0xc1和0xf5..0xFF不能以有效的UTF-8显示。还可以看到非常好的、不好的UTF-8示例测试数据
型
你不能先读四个字符,然后决定怎么做。如果字符是在0x00-0x7f中,则将丢弃其余的字符,或者必须以更困难的方式处理它们。
正确的方法是读一个字符。它将告诉您需要多少额外的字符,如果有的话,基于最重要的位是1。然后读取额外的字符,并转换为适当的Unicode码位,通过移动和忽略最重要的位在需要时。
您可以检查链接到的文档,以查看Unicode代码点的位是如何分布到几个字节的。以下是算法的简要说明:
百万千克1读取一个字节百万千克1百万千克1如果最上面的位为零,则无需执行其他操作:代码点为0x00-0x7F百万千克1百万千克1如果最上面的三个位是110,则需要另外一个字节。从第一个字节中取五个最低的位,将它们左移六位,或从第二个字节中移到最低的六位,得到最终值。百万千克1百万千克1如果最上面的四位是1110,则需要两个额外的字节。取第一个字节的四个最低位,移动12位,或从第二个字节移动6位的六个最低位,最后是第三个字节的六个最低位。百万千克1百万千克1如果最上面的五位是11110,那么您需要三个额外的字节,并像以前一样读取它们、移位等。百万千克1百万千克1如果这些条件都不符合,则数据无效百万千克1百万千克1请注意,当读取额外的字节时,这些字节必须将10作为最重要的位;任何其他的都是无效的。百万千克1
型
更低的代码甚至不起作用,因为c从未给定值,所以if条件将不定义。它也不能正确地检查字节,因此代码对您没有太大帮助。
- 好吧,我理解你对下面代码的回答……但我不确定我完全理解你第二段的意思。你能解释更多吗?
- @科斯塔斯迪补充说明了该怎么做
- 这包括了基本的内容——它将读取有效的UTF-8,并拒绝非常无效的UTF-8(可能对OP足够)。对于完全验证,还有一些附加要求,例如:拒绝非最小编码(0xc0 0x80是非最小编码,因此U+0000的编码无效;有效编码是0x00);不允许使用UTF-16代理项(U+D800..U+DFFF);超出U+0000..U+10FFFF范围的值无效。