4
FILE * f = fopen("filename", "r");
int c;

while((c = fgetc(f)) != EOF) {
    printf("%c\n", c);
}

您好,我已经搜索了整整一个小时,找到了许多关于 Unicode 的明智论文,但没有回答这个简单的问题:

在使用 gcc 和 bash 的 Linux 上,可以管理 UTF8 的这四行的最短等效项是什么。

谢谢

4

1 回答 1

6

考虑到您的系统,这样的事情应该可以工作:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>


int main() {
   setlocale(LC_CTYPE, "en_GB.UTF-8");
   FILE * f = fopen("filename", "r");
   wint_t c;

   while((c = fgetwc(f)) != WEOF) {
      wprintf(L"%lc\n", c);
   }
}

您的原始代码的问题在于 C 没有意识到(或关心)字符是多字节的,因此您的多字节字符将被\n每个字节之间的字符破坏。在此版本中,一个字符被视为 UTF-8,因此%lc现在可以表示多达 6 个实际字节,这些字节可以保证正确输出。如果输入有任何 ASCII,它将像以前一样简单地每个字符使用一个字节(因为 ASCII 与 UTF-8 兼容)。

strace对于调试这样的事情总是有用的。例如,如果文件仅包含££(£ 具有 UTF-8 序列 \302\243)。您的版本产生:

write(1, "\302\n\243\n\302\n\243\n\n\n", 10) = 10

而我的,

write(1, "\302\243\n\302\243\n", 6)     = 6

请注意,一旦您读取或写入流(包括stdout),它将被设置为字节或宽方向,如果您想更改它,您需要重新打开流。因此,例如,如果您想读取 UTF-8 文件,但保持stdout面向字节,则可以将其替换为wprintf

  printf("%lc\n", c);

这涉及后台的额外代码(以转换格式),但与其他需要字节流的代码提供更好的兼容性。

于 2013-03-16T17:15:42.777 回答