【问题标题】:Handling special characters in C (UTF-8 encoding)处理 C 中的特殊字符(UTF-8 编码)
【发布时间】:2010-11-25 07:11:09
【问题描述】:

我正在用 C 语言编写一个小型应用程序,它读取一个简单的文本文件,然后逐行输出。问题是文本文件包含特殊字符,如 Æ、Ø 和 Å 等。当我在终端中运行程序时,这些字符的输出用“?”表示。

有简单的解决方法吗?

【问题讨论】:

    标签: c macos encoding utf-8 terminal


    【解决方案1】:

    第一件事:

    1. 读入缓冲区
    2. 使用 libiconv 或类似工具从 UTF-8 获取 wchar_t 类型,并使用 wprintf() 等宽字符处理函数
    3. 在 C 中使用宽字符函数!大多数文件/输出处理函数都有宽字符变体

    确保您的终端可以处理 UTF-8 输出。拥有正确的语言环境设置和操作语言环境数据可以自动为您打开和转换大量文件……这取决于您在做什么。

    记住,UTF-8 中代码点或字符的宽度是可变的。这意味着您不能只寻找一个字节并像使用 ASCII 一样开始阅读……因为您可能会落在代码点的中间。在某些情况下,好的库可以做到这一点。

    这里有一些代码(不是我的),演示了 C 中 UTF-8 文件读取和宽字符处理的一些用法。

    #include <stdio.h>
    #include <wchar.h>
    int main()
    {
        FILE *f = fopen("data.txt", "r, ccs=UTF-8");
        if (!f)
            return 1;
    
        for (wint_t c; (c = fgetwc(f)) != WEOF;)
            printf("%04X\n", c);
    
        fclose(f);
        return 0;
    }
    

    链接

    1. libiconv
    2. Locale data in C/GNU libc
    3. Some handy info
    4. Another good Unicode/UTF-8 in C resource

    【讨论】:

    • 没问题。坚持下去,C 中的 Unicode 并不是世界上最简单的东西……也要熟悉标准 :)
    【解决方案2】:

    确保您不会意外丢失任何字节;一些 UTF-8 字符的长度超过一个字节(这就是重点),您需要保留它们。

    将缓冲区的内容打印为十六进制会很有用,因此您可以检查实际读取了哪些字节:

    static void print_buffer(const char *buffer, size_t length)
    {
      size_t i;
    
      for(i = 0; i < length; i++)
        printf("%02x ", (unsigned int) buffer[i]);
      putchar('\n');
    }
    

    您可以在加载一个非常短的文件(仅包含几个字符)后执行此操作。

    还要确保终端设置为正确的编码,以便将您的字符解释为 UTF-8。

    【讨论】:

    • 我的终端设置为 UTF-8 编码。程序通过 fgets() 将文本文件中每一行的所有字符存储到一个 char 数组中;如果我丢失字节,我不知道为什么或如何修复它......(刚开始学习 C 顺便说一句)
    • @Eirik,不要使用面向 ASCII 的 fgets()。使用我帖子中的 fgetwc()。
    【解决方案3】:

    您的文本文件可能是 ISO-8559-1 编码的,但您的终端是 UTF-8。这种不匹配是处理面向字节的文本处理时的标准问题;其他 C 程序(例如标准的“cat”和“more”命令)会执行相同的操作,通常不会将其视为错误或需要修复的问题。

    如果您想在 Unicode 字符级别而不是字节上进行操作,那很好,但您需要在整个程序中使用 wchar 而不是 char 作为字符类型,并为用户提供开关以指定传入文件的内容编码实际上是。 (虽然有时可以猜到,但不是很可靠。)

    【讨论】:

      【解决方案4】:

      我不知道它是否有帮助,但如果你确定终端和输入文件的编码是相同的,你可以尝试setlocale()

      #include <locale.h>
      …
      setlocale(LC_CTYPE, "");
      

      【讨论】:

      • 我使用了setlocale(LC_CTYPE, "UTF-8");。尽管正确配置了 shell 环境,但必须成功读取文件。
      • 使用setlocale(LC_CTYPE, ""),根据环境变量设置每个需要修改的locale部分。
      • 哦,是的,抱歉,应该是 "" 而不是 NULL
      猜你喜欢
      • 2020-09-20
      • 2014-02-14
      • 2011-02-21
      • 2019-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-03
      相关资源
      最近更新 更多