在现代C++中正确使用UTF - std类型和字符串容器

Poe*_*odu 10 c++ unicode encoding locale utf

简短版本:
如果我想写一个无错误的程序,可以安全且可能有效地执行UTF-8/16/32编码操作,我应该遵守哪些规则?
我特别想知道的东西列在长版下面.

长版:
在我的业余生涯中,我学到了很多C++,但直到今天我还没有尝试完全理解字符编码和语言环境.我可以想象,像内存管理有其规则,使您的程序安全,没有泄漏和不可预测的行为,所以他们有字符编码.Inb4:我已经完成了关于这个主题的研究,一直在浏览cppreference并学习了很多新的类,函数和库,但是如果没有足够的解释,我就无法完全理解它.此外,我找不到任何好的而不是过时<locale>的诀窍.所以,继续前进 - 如果我不得不使用标准库字符串编写多语言应用程序:

  • 我应该选择哪个字符串容器?
    • std::string 用UTF-8?
    • std::wstring (真的不太了解它)
    • std::u16string 用UTF-16?
    • std::u32string 用UTF-32?
  • 我应该完全坚持使用上述容器中的一个或在需要时更换它们吗?
  • 在使用UTF字符串时,我可以在字符串文字中使用非英文字符,例如波兰字符:????????等等?
  • 当我们存储UTF-8编码字符时会发生什么变化std::string?它们是否仅限于一个字节的ASCII字符,还是可以是多字节的?
    当我执行以下操作时会发生什么?

    std::string s = u8"foo";
    s += 'x';
    
    Run Code Online (Sandbox Code Playgroud)
  • wchar_t和其他多字节字符类型有什么区别?是wchar_t字符或wchar_t字符串文字能够存储UTF编码的?

根据标题,我问的是C++语言的最新特性 - 来自C++ 17,C++ 14和C++ 11标准.

编辑:
很少有人指出,上面的一些问题是一个非常大的主题,值得单独提问.TODO:添加问题的链接.

Rem*_*eau 10

我应该选择哪个字符串容器?

这取决于您根据自己的特殊需求来决定.您提出的任何选择都有效,它们各有各的优缺点.通常,UTF-8很适合用于存储和通信目的,并且向后兼容ASCII.而UTF-16/32在处理Unicode数据时更容易使用.

std::wstring (真的不太了解它)

大小wchar_t依赖于编译器,甚至取决于平台.例如,在Windows上,wchar_t是2个字节,std::wstring可用于UTF-16编码的字符串.在其他平台上,wchar_t可能是4个字节,而是std::wstring可用于UTF-32编码的字符串.这就是为什么wchar_t/ std::wstring通常不用于可移植代码,以及为什么char16_t/ std::u16stringchar32_t/ std::u32string在C++ 11中引入.

我应该完全坚持使用上述容器中的一个或在需要时更换它们吗?

使用适合您需要的任何容器.

通常,您应该在整个代码中使用一种字符串类型.仅在字符串数据进入/离开程序的边界处执行数据转换.例如,在读/写文件,网络通信,平台系统调用等时.

如何在它们之间正确转换?

有很多方法可以解决这个问题.

C++ 11及更高版本有std::wstring_convert/ std::wbuffer_convert.

有第三方Unicode转换库,如ICONV,ICU等.

有C库函数,平台系统调用等.

在使用UTF字符串时,我可以在字符串文字中使用非英文字符,例如波兰字符:????????等等?

是的,如果您使用适当的字符串文字前缀:

u8 对于UTF-8

L 对于UTF-16或UTF-32(取决于编译器/平台)

u16 对于UTF-16

u32 对于UTF-32

当我们存储UTF-8编码字符时会发生什么变化std::string?它们是否仅限于一个字节的ASCII字符,还是可以是多字节的?

它们可以是多字节的.就像std::wstring(当wchar_t是2个字节时)并且std::u16string可以保存包含BMP之外的补充字符的字符串,这需要UTF-16代理进行编码.

当字符串容器包含UTF编码的字符串时,每个"字符"只是一个UTF编码的代码单元.UTF-8编码的Unicode一个码点为1-4 CODEUNITS(1-4 char在A S std::string).UTF-16编码码点1-2 CODEUNITS(1-2 wchar_t秒/ char16_t在A S std::wstring/ std::u16string).UTF-32编码码点作为1个codeunit(1个char32_t中的1 个std::u32string).

当我执行以下操作时会发生什么?

std::string s = u8"foo";
s += 'x';
Run Code Online (Sandbox Code Playgroud)

正是你所期望的.A std::string持有char元素.无论编码如何,operator+=(char)都只需将单个追加char到最后std::string.

我怎么能区分UTF char[]和非UTF char[]还是std::string

您必须对char[]/ std::stringdata 执行自己的启发式分析,以查看它是否符合UTF.

wchar_t和其他多字节字符类型有什么区别?

字节大小和UTF编码.

char = ANSI/MBCS或UTF-8

wchar_t = UTF-16或UTF-32,具体取决于编译器/平台

char16_t = UTF-16

char32_t = UTF-32

wchar_t字符或wchar_t字符串文字是否能够存储UTF编码?

是,UTF-16或UTF-32,具体取决于编译器/平台.对于UTF-16,单个wchar_t只能保存BMP中的代码点值.wchar_tUTF-32中的单个可以保存任何代码点值.甲wchar_t字符串可以编码所有的码点在任一编码.

如何正确操作UTF字符串(例如toupper/tolower转换)并同时兼容语言环境?

这是一个非常广泛的话题,值得单独提出问题.