提问人:Jacob 提问时间:10/13/2023 更新时间:10/13/2023 访问量:98
使用 MSVC 在 Windows 上将“\n”重新解释为 UTF16
Reinterpreting "\n" to UTF16 on Windows with MSVC
问:
我正在尝试编写简单的程序,将大的 txt 文件划分为较小的文件。当涉及到 UTF16 编码文件时,问题就开始了。无论我如何尝试,例如,如果我们在 UTF16 LE 文件行中以“0D 00 0A 00”结尾,在除法后它是“0D 00 0D 0A 00”,或者如果是 UTF16 BE“00 0D 00 0A”,它会变成“00 0D 00 0D 0A”。这意味着每次我都要保存“0D 0A”字节。在评论中尝试了不同的方法,如下所示。我唯一的想法是在二进制模式下运行,不想使用 std 以外的其他库。任何线索都值得赞赏。
std::wifstream winfile;
std::wofstream woutfile;
using namespace std;
int main()
{
std::wstring line, temp;
unsigned int limit;
unsigned int part = 1;
//(...)
while (!winfile.eof()) {
limit = 1000000;
woutfile.open(save_path + std::to_string(part) + ".txt", std::ios::out | std::ios::app);
limit--;
while (limit > 0 && !winfile.eof()) {
getline(winfile, temp);
wchar_t lf[]{ L'\n'};
woutfile << temp << lf;
/*
wchar_t lf[]{ 0x00, 0x0D, 0x00, 0x0A};
woutfile << temp << lf;
woutfile << temp << L"\n";
woutfile << temp << std::endl;
*/
limit--;
}
part++;
winfile.close();
woutfile.close();
}
system("pause");
}
答:
0赞
Adrian McCarthy
10/13/2023
#1
我们可以看到您的输出流处于文本模式。听起来您的输入流处于二进制模式(或者它是 UTF-16 的事实搞砸了对行尾的解释)。
使用二进制输入,您将读取回车符 (CR) 和换行符 (LF) 字符。
std::getline 的默认分隔符是 ,它恰好是几乎所有实现中的换行符。因此,getline 将回车符视为另一个字符,并在换行符处划分行。因此,生成的字符串以回车符结束,您将其写回。然后,在行后写入,并且由于输出流处于文本模式,因此该流被转换为CR+LF。因此,输出字符串以 CR+CR+LF 结尾。'\n'
'\n'
您可以通过以下几种方式处理此问题:
以文本模式打开输入,如有必要,按照注释中建议@RemyLebeau进行输入。
在二进制模式下执行所有操作。
保持一切不变,但在将每行发送到输出流时跳过任何尾随回车。
评论
0赞
Jacob
10/13/2023
我没有使用二进制模式,所以读取问题来自源文件是 UTF-16 编码的。我将尝试使用 imbue 和 std::locale,否则二进制模式和使用 endianess 进行处理是解决方案。第三个命题是行不通的,我会向左剪掉 0D00 或 000D,但用任何方法保存的 CRLF 仍然是错误的,我也试过了。
评论
write("\r\n", 2)
while (!stream.eof()))
被认为是错误的?wchar_t lf[]{ L'\n'}; woutfile << temp << lf;
是一个错误和未定义的行为。 根本没有做任何事情(它是一个空字符串)。wchar_t lf[]{ 0x00, 0x0D, 0x00, 0x0A}; woutfile << temp << lf;
lf
imbue()
std::locale