18

我正在开发一个仅适用于 Windows 的英语 C++ 程序,我们被告知“始终使用 std::wstring”,但似乎团队中没有人真的对此有太多了解。

我已经阅读了题为“std::wstring VS std::string的问题。它非常有帮助,但我仍然不太明白如何将所有这些信息应用于我的问题。

我正在处理的程序在 Windows GUI 中显示数据。该数据以 XML 形式保存。我们经常使用 XSLT 将 XML 转换为 HTML 或 XSL:FO 以用于报告目的。

根据我阅读的内容,我的感觉是 HTML 应该编码为 UTF-8。我对 GUI 开发知之甚少,但我读过的一点点表明 GUI 的东西都是基于 UTF-16 编码的字符串。

我试图了解这让我离开了哪里。假设我们决定我们所有的持久化数据都应该是 UTF-8 编码的 XML。这是否意味着为了在 UI 组件中显示持久数据,我真的应该执行某种明确的 UTF-8 到 UTF-16 转码过程?

我怀疑我的解释可能需要澄清,所以如果您有任何问题,我会尽力提供。

4

5 回答 5

9

从 NT4 开始的 Windows 是基于 Unicode 编码的字符串,是的。早期版本基于 UCS-2,它是 UTF-16 的前身,因此不支持 UTF-16 支持的所有字符。更高版本基于 UTF-16。不过,并非所有操作系统都基于 UTF-16/UCS-2。例如,*nix 系统是基于 UTF-8 的。

UTF-8 是持久存储数据的一个非常好的选择。它是所有 Unicode 环境中普遍支持的编码,在数据大小和无损数据兼容性之间取得了很好的平衡。

是的,您必须解析 XML,从中提取必要的信息,然后将其解码并转换为 UI 可以使用的内容。

于 2010-03-27T01:06:49.420 回答
7

std::wstring 在技术上是 UCS-2:每个字符使用两个字节,代码表大多映射到 Unicode 格式。重要的是要了解 UCS-2 与 UTF-16 不同!UTF-16 允许“代理对”以表示超出两字节范围的字符,但 UCS-2 对每个字符(句点)恰好使用两个字节。

对于您的情况,最好的规则是在读取和写入磁盘时进行转码。一旦它在内存中,将其保存为 UCS-2 格式。Windows API 会将其读取为 UTF-16(也就是说,如果您手动创建代理对,则 std::wstring 不理解代理对的概念(如果您唯一的语言是英文),Windows 会读取它们)。

在现代,无论何时从序列化格式(如 XML)中读取或读取数据,都可能需要进行转码。这是生活中令人不快且非常不幸的事实,但这是不可避免的,因为 Unicode 是一种可变宽度字符编码,并且 C++ 中大多数基于字符的操作都是作为数组完成的,因此您需要一致的间距。

更高级别的框架,例如 .NET,掩盖了大部分细节,但在幕后,它们以相同的方式处理转码:将可变宽度数据更改为固定宽度字符串,操作它们,然后更改它们输出需要时返回可变宽度编码。

于 2010-03-27T01:12:58.827 回答
6

AFAIK,当您在 C++ 中的 Windows 上使用 std::wstring 并使用 UTF-8 存储在文件中(这听起来不错且合理)时,您必须在写入文件时将数据转换为 UTF-8,然后转换回从文件读取时使用 UTF-16。查看此链接:Writing UTF-8 Files in C++

我会坚持使用 Visual Studio 默认的项目 -> 属性 -> 配置属性 -> 常规 -> 字符集 -> 使用 Unicode 字符集,使用 wchar_t 类型(即使用 std::wstring)而不使用 TCHAR 类型。(例如,我只使用 wcslen 版本的 strlen 而不是_tcslen。)

于 2010-03-27T02:49:34.497 回答
3

在 Windows 上为 GUI 相关字符串使用 std::wstring 的一个优点是,在内部所有 Windows API 调用都使用 UTF-16 并在其上运行。如果您曾经注意到有 2 个版本的所有 Win32 API 调用都采用字符串参数。例如,“MessageBoxA”和“MessageBoxW”。这两个定义都存在于 中,实际上你可以调用任何你想要的,但如果包含在启用 Unicode 支持的情况下,则会发生以下情况:

#define MessageBox MessageBoxW

然后,您将了解 TCHAR 和其他 Microsoft 技巧,以尝试更轻松地处理同时具有 ANSI 和 Unicode 版本的 API。简而言之,您可以调用其中任何一个,但在基于 Unicode 的 Windows 内核的底层,因此如果您不使用宽字符版本,您将为接受 Win32 API 调用的每个字符串支付转换为 Unicode 的费用。

UTF-16 和 Windows 内核使用

于 2010-03-27T01:07:50.573 回答
1

即使您说您的数据中只有英语,您也可能错了。由于我们现在处于一个全球化的世界,名称/地址/等都有外来字符。好的,我不知道您拥有什么类型的数据,但通常我会说构建您的应用程序以支持 UNICODE 来存储数据和向用户显示数据。这将建议您在执行 GUI 时使用带有 UTF-8 的 XML 来存储和 UNICODE 版本的 Windows 调用。由于 Windows GUI 使用 UTF-16,其中每个令牌都是 16 位,我建议将应用程序中的数据存储在 16 位宽的字符串中。而且我猜你的 Windows 编译器会将 std::wstring 设置为 16 位来达到这个目的。

因此,您必须在 UTF-16 和 UTF-8 之间进行大量转换。使用一些现有的库来做到这一点,例如ICU

于 2010-03-27T02:03:46.317 回答