提问人:James P 提问时间:10/13/2023 最后编辑:James P 更新时间:10/14/2023 访问量:93
getline() 在读取 UTF-8 表情符号字符时到达文件末尾
getline() reaches end of file when reading UTF-8 emoji character
问:
我正在编写一个处理大型分隔文件的 C++ 程序。
我有一个UTF-8 csv文件,其中包含一行带有(emoji?)字符🌟。它看起来像这样:
123,"james","piotrj🌟","1996-01-28"
当我调用这一行时,它会读取表情符号,然后停止。因此,生成的字符串是 。我不确定为什么会这样。如果我不得不猜测,我不正确地使用了语言环境,并且这个表情符号(或其中的一部分)被读取为 .getline()
getline()
123,"james","piotrj
EOF
我想按原样读取这一行,执行一些字符串操作,然后将其写出到另一个文件中。
我这里有一些示例代码:
locale loc("en_US.UTF8");
wifstream inFile;
inFile.imbue(loc);
inFile.open("MyFile.csv");
if(inFile.is_open()){
wstring str;
if (getline(inFile, str)) {
wcout << str << endl;
}
if (getline(inFile, str)) {
wcout << str << endl;
}
inFile.close();
}
此代码的输出为:。第二个 if 语句正文不执行,因为第二个语句没有抓取任何内容。123,"james","piotrj
getline()
为了尝试一些事情,我将语言环境更改为:
locale loc = locale();
语言环境的名称是“C”,这将得到整行。该程序的输出为:。这是朝着正确方向迈出的一步,但如果没有正确的语言环境,wstring 将无法正确存储它。在我的程序中,我做了一些单独的字符检查,看看字符串是否可以用ANSI表示,因此我真的希望wstring将该表情符号作为一个字符。123,"james","piotrj≡ƒîƒ","1996-01-28"
答:
看起来您正在使用 libc++。此实现中的宽流根本不支持 UTF-8。
如果你改用 libstdc++,你的程序可以工作,除了你会在输出中得到音译文本。我得到
123,"james","piotrj?","1996-01-28"
那是因为语言环境没有注入 .要获取普通文本,您需要执行以下任一操作wcout
ios_base::sync_with_stdio(false);
wcout.imbue(loc);
(如果区域设置与 STDIO 同步,则无法将其注入标准流中)
或者,
locale::global(loc);
然后你的程序将完全工作。
如果您绑定到 libc++,您唯一的选择是使用窄字符流。
编辑:使用MSVC,此代码也不起作用。不知道为什么Microsoft声称在较新版本的Windows中支持UTF-8,显然它根本不存在。在 Windows 上,可以安装 gcc(几种风格之一,我推荐 MSYS2 提供的 UCRT 风格)。我不能保证它会起作用,因为最终控制流会通过 Microsoft 运行时库。正确的解决方案是永远不要使用任何 API,除了调用需要 .使用窄字符,从文件中读取 UTF-8,以 UTF-8 格式存储和操作字符串,以 UTF-8 格式输出。我已经测试了使用 MSVC 转换为窄字符的代码,它对我来说按预期工作。wchar_t
wchar_t
评论