如何读取和打印 unicode 文件

How to read and print a unicode file

我有一个测试输入文件 input.txt 其中一行包含以下内容:

кёльнский

我正在使用此代码尝试读入并打印出来。

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

int main()
{
    FILE *input;
    wchar_t buf[1000];

    setlocale(LC_CTYPE,"");   

    if ((input = fopen("input.txt","r")) == NULL)
         return 1;

    printf("Read and print\n");
    while (fgetws(buf,1000,input)!=NULL)
        wprintf(L"%s",buf);

    fclose(input);
}

然而,当我 运行 它时,我看到“读取和打印”,然后什么也没有。

我正在 Ubuntu 上用 gcc 编译。

我做错了什么?


事实证明,用

替换 wprintf 行
printf("%ls",buf);

解决了问题。

这是为什么?

fgetws 读取 UTF-16。我们通常将带有普通 fgets 的 UTF-8 处理成 char [] 并期望它能够工作并使用普通 printf 打印它。这就是 UTF-8 的意义所在。如果它在显示器上不起作用,则可能是您的终端不是 UTF-8;这很容易通过 运行 cat input.txt.

检查

你做错了两件事:

  1. 将普通(面向字节)和宽输出函数混合到标准输出。你需要坚持其中一个。来自 C11 草案,第 7.21.2 节:

Each stream has an orientation. After a stream is associated with an external file, but before any operations are performed on it, the stream is without orientation. Once a wide character input/output function has been applied to a stream without orientation, the stream becomes a wide-oriented stream. Similarly, once a byte input/output function has been applied to a stream without orientation, the stream becomes a byte-oriented stream. ...

Byte input/output functions shall not be applied to a wide-oriented stream and wide character input/output functions shall not be applied to a byte-oriented stream.

  1. 使用错误的 printf 格式打印宽字符串。 %s 用于普通 char 字符串。 %ls 用于 wchar_t 字符串。但是如果只是将宽字符串打印到宽流,则更喜欢 fputws()。如果您实际上没有使用 printf 的格式化功能或将文字文本与变量混合或将宽字符打印到面向字节的流或其他花哨的东西,则使用 printf 函数毫无意义。

解决上述问题的一种方法(在许多替代方法中)将标准输出视为面向广泛的流:

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

int main(void)
{
    FILE *input;
    wchar_t buf[1000];

    setlocale(LC_CTYPE,"");   

    if ((input = fopen("input.txt","r")) == NULL)
         return 1;

    fputws(L"Read and print\n", stdout);
    while (fgetws(buf,1000,input)!=NULL)
        fputws(buf, stdout);

    fclose(input);
}

另一种,使用面向字节的标准输出:

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

int main()
{
    FILE *input;
    wchar_t buf[1000];

    setlocale(LC_CTYPE,"");

    if ((input = fopen("input.txt","r")) == NULL)
         return 1;

    puts("Read and print");
    while (fgetws(buf,1000,input)!=NULL)
      printf("%ls", buf);

    fclose(input);
}