FILE * f = fopen("filename", "r");
int c;
while((c = fgetc(f)) != EOF) {
printf("%c\n", c);
}
您好,我已经搜索了整整一个小时,发现了很多关于Unicode的明智论文,但没有回答这个简单的问题:
这四行的最短等价物,可以在Linux上使用gcc和bash来管理UTF8。
谢谢
答案 0 :(得分: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);
这涉及后台的额外代码(转换格式),但提供了与期望字节流的其他代码更好的兼容性。