该程序只能使用C标准的库。
我正在尝试使用
fwscanf
在 C 中读取 UTF-8 编码的 CSV 文件,但我在读取过程中遇到了问题。该文件包含带有字符串和以逗号分隔的浮点值的行。这是演示该问题的最小示例:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
#define MAX_STRING_LENGTH 31
int main() {
setlocale(LC_ALL, "en_US.UTF-8");
FILE *file = fopen("input.csv", "r, ccs=UTF-8");
if (file == NULL) {
fwprintf(stderr, L"Error opening file.\n");
return 1;
}
wchar_t string[MAX_STRING_LENGTH];
float frequency;
int row = 0;
while (!feof(file)) {
row++;
int result = fwscanf(file, L"%30[^,],%f,", string, &frequency);
if (result == 2) {
wprintf(L"Row %d: String = '%ls', Frequency = %.4f\n", row, string, frequency);
} else if (result == 1) {
wprintf(L"Row %d: String = '%ls', Frequency not read\n", row, string);
} else if (result == EOF) {
break;
} else {
wprintf(L"Error reading row %d\n", row);
wchar_t c;
// Skip the rest of the line
while ((c = fgetwc(file)) != L'\n' && c != WEOF);
}
}
fclose(file);
return 0;
}
示例输入.csv:
hello,1.0000
world,0.5000
how,0.7500
are,0.2500
you,1.0000
?,0.5000
预期输出:
Row 1: String = 'hello', Frequency = 1.0000
Row 2: String = 'world', Frequency = 0.5000
Row 3: String = 'how', Frequency = 0.7500
Row 4: String = 'are', Frequency = 0.2500
Row 5: String = 'you', Frequency = 1.0000
Row 6: String = '?', Frequency = 0.5000
我面临的问题是 fwscanf 无法正确读取文件。它要么读取不正确的值,要么根本无法读取。我尝试过使用不同的区域设置和文件打开模式,但问题仍然存在。
参数
string
与L"%30[^,],%f,"
格式字符串不一致。 %[
需要一个指向 char
数组的指针,该数组将接收从流读取的宽字符到其多字节表示形式的转换。
您想要执行一项非常不同的任务:将 UTF-8 编码的输入流转换为宽字符串。 您应该使用
fscanf("%30l[^,],%f,", string, &frequency)
来代替。
诸如
fwscanf()
之类的面向广泛的I/O函数不适合您的用例。 他们期望输入为一系列宽字符(其中实现有一定的自由度来定义其含义),但 UTF-8 输入不是这样。 实现可能会有所不同,但您的 fwscanf
调用可能会尝试读取文件,就好像它是用 UCS-2 编码的一样。
C 具有“多字节字符”的含义,与“宽字符”分开且不同。 前者由两个或多个
char
单元组成,它们最自然地存储在 char
数组中,可能散布有单字节字符。 后者由单个 wchar_t
组成,并且最自然地存储在 wchar_t
数组中,在这种情况下,它们不能散布单字节字符。
您的 UTF-8 输入最适合前者,并且面向字节的 I/O 函数最适合读取和写入它们。 (终端或其他显示设备负责“解释”代码序列,以便呈现相应的图形表示。)顺便说一句,C 从 C11 开始就有 UTF-8 文字,它们对应于 char
的数组.
。 使用窄 I/O 函数和常规字符串,而不是宽导向 I/O 函数和宽字符串。
此外,