从 C 语言中的文件中读取 unicode 字符



我正在尝试从.csv文件中读取UTF-8字符串,然后将其写入控制台。

A.csv内容:

Gijón

经过一整天对该主题的研究,我发现执行此类操作的正确方法应类似于以下内容:

int main(int argc, char *argv[])
{
char *locale = setlocale(LC_ALL, "");
printf("locale: %sn", locale);
const int MAX_LINE_SIZE = 1024;
char line[MAX_LINE_SIZE];
wchar_t wline[MAX_LINE_SIZE];
// Attempt 0: no special handling
FILE* stream = fopen("a.csv", "r");
fgets(line, MAX_LINE_SIZE, stream);
printf("%sn", line); // Expected to print "Gijón", prints "Gijón"
fclose(stream);
// Attempt 1: mbstowcs
mbstowcs(wline, line, MAX_LINE_SIZE);
wprintf(L"%lsn", wline); // Expected to print "Gijón", prints "Gijón"
// Attempt 2: fgetws
stream = fopen("a.csv", "r");
fgetws(wline, MAX_LINE_SIZE, stream);
wprintf(L"%lsn", wline); // Expected to print "Gijón", prints "Gijón"
fclose(stream);
// Attempt 3: _wfopen
stream = _wfopen(L"a.csv", L"rb");
fgetws(wline, MAX_LINE_SIZE, stream);
wprintf(L"%lsn", wline); // Expected to print "Gijón", prints ""
fclose(stream);
// Printing command line parameter
mbstowcs(wline, argv[1], MAX_LINE_SIZE);
wprintf(L"%lsn", wline); // Properly prints "Gijón"
}

但是运行此程序会导致:

.myprogram.exe Gijón
locale: Spanish_Spain.1252
Gijón
Gijón
Gijón

我不认为这是控制台本身的问题,因为argv[1]转换工作正常。

我错过了什么?

>wchar_t和宽字符函数(wfopen等(主要用于Windows中处理UTF16编码的Unicode。

UTF8 使用char和相同的 ASCII 兼容 C 函数(fopen等(要读取 UTF8,您可以对 ASCII 使用相同的 C 函数。

Windows 没有完全支持读取和显示 UTF8,因此您必须在 UTF8 和 UTF16 之间进行转换才能正确显示文本。Windows 10 确实对控制台 Windows 提供 UTF8 支持,请参阅相关主题。

#include <stdio.h>
#include <windows.h>
int main(void)
{
const char* filename = "a.csv";
FILE* fp = fopen(filename, "r");
char buf[1000];
fgets(buf, sizeof(buf), fp);
if(strlen(buf) > 2)
if(strncmp(buf, "xFFxFE", 2) == 0)
{
printf("UTF16-LEn");
fclose(fp);
fp = fopen(filename, "rb");
wchar_t wbuf[1000] = { 0 };
fgets((char*)wbuf, sizeof(buf), fp);
MessageBoxW(0, wbuf, L"UTF16-LE", 0);
return 0;
}
if(strlen(buf) > 3)
if(strncmp(buf, "xEFxBBxBF", 3) == 0)
printf("UTF8 with BOMn");
//assume UTF8 and convert to UTF16:
int size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0);
wchar_t *utf16 = malloc((size + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, buf, -1, utf16, size);
MessageBoxA(0, buf, "ANSI", 0);
MessageBoxW(0, utf16, L"UTF8 converted", 0);
return 0;
}

如果源文件是 UTF8,那么您基本上将其视为 ASCII。请注意像strtok这样的函数,它们不能处理 ASCII 范围之外的输入字符。唯一的其他复杂情况是当您尝试在Windows中打印它时。将以下示例与自定义printf函数一起使用:

void printf_utf8(const char* format, ...)
{
va_list args;
va_start(args, format);
int len = _vscprintf(format, args) + 1; 
char *buf = malloc(len);
vsprintf(buf, format, args);
//convert to UTF16 and print
int wbuf_size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0);
wchar_t *wbuf = malloc((wbuf_size + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, wbuf_size);
DWORD temp;
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleW(h, wbuf, wcslen(wbuf), &temp, 0);
free(wbuf);
free(buf);
}
int main(void)
{
FILE* fp = fopen("a.csv", "r");
if(!fp)
return 0;
char buf[1000];
fgets(buf, sizeof(buf), fp);
printf_utf8("Test %s %dn", buf, 123);
return 0;
}

我认为您必须将宽字符转换为 1252 编码。1252 编码是 8 位/字符编码,仅支持 unicode 字符的一小部分。 也许有可用的转换函数/库。但是自己写似乎不太复杂(大开关/案例子句(。

最新更新