使用 getchar() 在 C 中进行 UTF-8 编码

nav*_*ian 2 c utf-8

我必须制作一个使用 UTF-8 编码的字符并将它们“翻译”成 Unicode 的代码。您可以在此处查看 UTF-8 是什么https://en.wikipedia.org/wiki/UTF-8。我是 C 初学者,所以我有三个限制:

  1. 我必须使用 getchar()
  2. 禁止使用数组
  3. 我只对 1、2、3 和 4 个字节的 Unicode 字符感兴趣

所以我有这个代码,它完全可以用于 4 个字节(我知道我必须使用!= EOF每个字节,getchar();但现在这不是我的问题)

#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\n");
                return 1;
        }
        c = ((ch1 & 0x07) << 18) | ((ch2 & 0x3F) << 12) |
                        ((ch3 & 0x3F) << 6) | (ch4 & 0x3F);
        printf("c = %05X\n", c);
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的问题:我无法理解如何使用getchar()1-2-3 个字节。我的意思是,我必须getchar在开始时阅读所有函数,然后使用ch11 字节字符和ch1, ch22 字节字符,或者我必须这样做。(顺便说一下,它下面的代码不起作用,它给了我一个无限循环;我只是把它用作我的想法的一个例子。)

#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\n");
                    return 1;   
                   }
                 c = ((ch1 & 0x80) << 7);
                 printf("c = %05X\n", c);
                }
        }
Run Code Online (Sandbox Code Playgroud)

Sam*_*nen 7

您不能通过先阅读四个字符然后决定要做什么来做到这一点。如果字符在 0x00-0x7f 中,您将把其余的都扔掉,或者您必须以更困难的方式处理它们。

正确的方法是读取一个字符。它会根据最高位为 1 来告诉您需要多少个额外字符(如果有)。然后读取额外的那些并在需要时通过移位和消除最高有效位来转换为正确的 UNICODE 代码点。

您可以查看链接到的文档以了解 UNICODE 代码点的位如何分布到多个字节。这里也简单解释一下算法:

  • 读取一个字节
  • 如果最高位为零,则无需执行其他操作:代码点为 0x00-0x7f
  • 如果最高三位是110,那么您需要一个额外的字节。取第一个字节的五个最低位,将它们左移六位,然后将第二个字节的最低六位进行 OR 运算,得到最终值
  • 如果最上面的四位是1110,那么您需要两个额外的字节。取第一个的最低四位,移12位,或从第二个字节的最低六位移六位,最后取第三个字节的最低六位
  • 如果最高的五位是11110,那么您需要三个额外的字节,并将像以前一样读取它们、移位等
  • 如果这些条件都不符合,则数据无效
  • 请注意,在读取额外字节时,这些字节必须具有10最高有效位;其他任何东西都是无效的。

较低的代码甚至不起作用,因为c从未给定值,因此if条件将是未定义的。它也不会正确检查字节,因此该代码对您没有太大帮助。

  • 这涵盖了基础知识——它将读取有效的 UTF-8 并拒绝极其无效的 UTF-8(对于 OP 来说可能就足够了)。对于完全验证,还有一些额外的要求,例如:拒绝非最小编码(0xC0 0x80 是非最小编码,因此 U+0000 的编码无效;有效编码为 0x00);不允许使用 UTF-16 代理 (U+D800..U+DFFF);超出范围 U+0000..U+10FFFF 的值无效。 (2认同)