在C中读取和打印Unicode和UTF-8编码
我正在使用Windows XP。在C中读取和打印Unicode和UTF-8编码,c,windows,unicode,character-encoding,console,C,Windows,Unicode,Character Encoding,Console,我正在使用Windows XP。 我想读取ASCII、UTF-8和Unicode编码的文件,并在标准输出上打印字符串。 我试图使用wchar.h中的函数,如fgetwc()/fputwc()和fgetws()/fputws(),它们在ASCII上工作,但在文件为UTF-8或Unicode时不工作。不打印特定于语言的字符,当文件使用Unicode时,它只打印方框和第一个字母。 有没有办法用纯C语言编写一个程序,它可以读取文件、比较字符串并在标准输出上正确打印出来,而不考虑输入程序的文件的编码 有没
我想读取ASCII、UTF-8和Unicode编码的文件,并在标准输出上打印字符串。
我试图使用wchar.h中的函数,如fgetwc()/fputwc()和fgetws()/fputws(),它们在ASCII上工作,但在文件为UTF-8或Unicode时不工作。不打印特定于语言的字符,当文件使用Unicode时,它只打印方框和第一个字母。
有没有办法用纯C语言编写一个程序,它可以读取文件、比较字符串并在标准输出上正确打印出来,而不考虑输入程序的文件的编码 有没有办法用纯C语言编写一个程序,它可以读取文件、比较字符串并在标准输出上正确打印出来,而不考虑输入程序的文件的编码
不,程序显然也要告诉我们文件的编码。在内部,您可以选择使用UTF-8中的多字节字符串或宽字符串来表示文件的数据。因为您在Windows上,关键是要使用函数写出字符串,首先要组装要写出的UTF-16字符序列。(一次可能只需写入几千字节的字符。)当然,可以使用
GetStdHandle
获取控制台句柄
更难的是确定文件的编码。幸运的是,您不需要区分ASCII和UTF-8,因为后者是前者的严格超集。但对于任何其他单字节编码,您都需要猜测。一些UTF-8文件(在Windows上比在其他地方更可能如此)在文件的开头有一个UTF-8编码的字节顺序标记;这很糟糕,因为BOM实际上不应该与UTF-8一起使用,但如果存在的话,它是一个强有力的指标。(发现UTF-16更容易,因为它应该有一个字节顺序标记,或者你可以从NUL(0)字节的存在中猜出来。)这里有一段代码,我用来打印Unicode的ASCII子集之外的各种字符(包含解决Open Watcom编译器的printf()实现中可能出现的错误的方法):
在Windows XP中,我没有找到一种直接将UTF-16代码点打印到控制台的方法,该方法的工作原理与上述方法相同。是的,有一种方法,但是“正确打印”对您意味着什么?它比什么更有效?我的意思是从比较的文件中读取非ASCII字母,例如觅čćđž,并打印在标准输出上。“Unicode”不是编码。@比利:是的,Windows也使用UTF-16表示宽字符串/字符。我从来没有说过它是“无效的”(不管这意味着什么)。你的文本说“UTF-8中的多字节字符串或宽字符串”--UTF-16和UTF-8一样都是“多字节”,但它也比字符更宽。(真正的“宽”字符串使用UTF-32/UCS-4)@Billy“多字节字符”和“宽字符”具有精确定义的含义(参见C99中的3.7.2和3.7.3),我指的就是这个意思。根据C,多字节字符和宽字符有定义的含义。它们对于Unicode没有意义。可以建立猜测编码的启发式方法,但很难做到完美。非常好的编码,谢谢。它让我了解了很多Windows特定编程的内幕。
// Compile with Open Watcom C/C++ 1.9: wcl386 cons-utf8.c
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
// Workarounds for printf() not printing multi-byte (UTF-8) strings
// with Open Watcom C/C++ 1.7-1.9.
// 0 - no workaround for printf()
// 1 - setbuf(stdout, NULL) before printf()
// 2 - fflush(stdout) after printf()
// 3 - WriteConsole() instead of printf()
#define PRINT_WORKAROUND 03
int main(void)
{
DWORD err, i, j;
// Code point ranges of characters to print
static const DWORD ranges[][2] =
{
{ 0x0A0, 0x0FF }, // Latin chars with diacritic marks + some others
{ 0x391, 0x3CE }, // Greek chars
{ 0x410, 0x44F } // Cyrillic chars
};
#if PRINT_WORKAROUND == 1
setbuf(stdout, NULL);
#endif
if (!SetConsoleOutputCP(CP_UTF8))
{
err = GetLastError();
printf("SetConsoleOutputCP(CP_UTF8) failed with error 0x%X\n", err);
goto Exit;
}
printf("Workaround: %d\n", PRINT_WORKAROUND);
for (j = 0; j < sizeof(ranges) / sizeof(ranges[0]); j++)
{
for (i = ranges[j][0]; i <= ranges[j][1]; i++)
{
char str[8];
int sz;
wchar_t wstr[2];
wstr[0] = i;
wstr[1] = 0;
sz = WideCharToMultiByte(CP_UTF8,
0,
wstr,
-1,
str,
sizeof(str),
NULL,
NULL);
if (sz <= 0)
{
err = GetLastError();
printf("WideCharToMultiByte() failed with error 0x%X\n", err);
goto Exit;
}
#if PRINT_WORKAROUND < 3
printf("%s", str);
#if PRINT_WORKAROUND == 2
fflush(stdout);
#endif
#else
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),
str,
sz - 1,
&err,
NULL);
#endif
}
printf("\n");
}
printf("\n");
Exit:
return 0;
}
C:\>cons-utf8.exe
Workaround: 3
¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ
АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя