读取多语言文件 - wchar_t vs char?

Kar*_*ari 3 c++

了解 unicode、语言环境、宽字符和转换对我来说是一次可怕的经历。

我需要读取包含俄语和英语,中国和乌克兰字符的文本文件一次全部

我的方法是以字节块读取文件,然后对块进行操作,在单独的线程上进行快速读取。(关联)

这是使用 std::ifstream.read(myChunkBuffer, chunk_byteSize)

但是,我知道如果我坚持使用char.


就此而言,我将一切都转化wchar_t为最佳状态并希望得到最好的结果。

我也知道Sys.setlocale(locale = "Russian") (链接),但它不是将每个字符解释为俄语吗?当我解析字节时,我不知道何时在我的 4 种语言之间切换。

在 Windows 操作系统上,我可以创建一个 .txt 文件并写上“??????!你好!” 在程序 Notepad++ 中,它将保存文件并以相同的字母重新打开。它是否以某种方式在每个字符后秘密添加隐形标记,以了解何时解释为俄语,何时解释为英语?


我目前的理解是:将所有内容都作为wchar_t(双字节),将任何文件解释为 UTF-16(双字节) - 是否正确?

另外,我希望保持代码跨平台。

对不起菜鸟

Pau*_*ers 5

霍凯,让我们这样做。让我们为从 UTF-8 编码文件读取文本并将其转换为宽字符串而不丢失任何信息的特定问题提供一个实用的解决方案。

一旦我们能做到这一点,我们应该就可以了,因为这里提供的实用函数通常会处理所有 UTF-8 到宽字符串的转换(反之亦然),而这正是您所缺少的关键。

那么,首先,您将如何读取数据?嗯,这很容易。因为,在一个层面上,UTF-8 字符串只是 的​​序列chars,出于多种目的,您可以简单地以这种方式对待它们。所以你只需要对任何文本文件做你会做的事情,例如:

std::ifstream f;
f.open ("myfile.txt", std::ifstream::in);
if (!f.fail ())
{
    std::string utf8;
    f >> utf8;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。这一切看起来很容易。

但是现在,为了更轻松地处理我们刚刚读入的字符串(因为在代码中处理多字节字符串是一件非常痛苦的事情),我们需要在尝试对其进行任何操作之前将其转换为所谓的宽字符串。这些实际上有几种风格(因为围绕wchar_t任何特定平台上实际“宽度”的不确定性),但现在我将坚持wchar_t保持简单,并且进行这种转换实际上比您想象的要容易思考。

因此,事不宜迟,这里是您的转换功能(这是您购买机票的目的):

#include <string>
#include <codecvt>
#include <locale>

std::string narrow (const std::wstring& wide_string)
{
    std::wstring_convert <std::codecvt_utf8 <wchar_t>, wchar_t> convert;
    return convert.to_bytes (wide_string);
}

std::wstring widen (const std::string& utf8_string)
{
    std::wstring_convert <std::codecvt_utf8 <wchar_t>, wchar_t> convert;
    return convert.from_bytes (utf8_string);
}
Run Code Online (Sandbox Code Playgroud)

我的,这很简单,为什么这些票一开始要花这么多钱?

我想这就是我真正需要说的。我认为,根据您在问题中所说的,您已经对自己想要做什么有了一个清晰的想法,只是不知道如何实现它(也许还没有完全连接所有的点还),但万一有任何挥之不去的困惑,一旦你这样做有一个宽字符串您可以自由使用所有性病的方法:: basic_string的就可以了,一切都将“只是工作”。如果您需要将其转换回 UTF-8 字符串以(例如)将其写出到文件中,那么现在这很简单。

在最优秀的Wandbox 上测试程序。我稍后会补上这个帖子,还有一些话要说。现在是早餐时间:) 请在评论中提出任何问题。

注释(作为编辑添加):

  • codecvt在 C++17 中不推荐使用(不知道为什么),但是如果你将它的使用限制为这两个函数,那么它真的没什么可担心的。如果出现更好的东西(提示,提示,亲爱的标准人员),人们总是可以重写这些内容。
  • codecvt 我相信可以处理其他字符编码,但就我而言,谁在乎?
  • 如果std::wstring(基于wchar_t)在您的特定平台上不适合您,那么您始终可以使用std::u16stringstd::u32string