Windows下的宽字符或UTF-8?

时间:2014-07-03 14:47:52

标签: c++ windows unicode utf-8 mfc

我们正在将Windows代码从旧版字符集转换为Unicode。我们的GUI代码使用MFC,但我们还有许多非GUI模块将被整合到非MFC环境中。

UTF-8是保存数据文件的最具前瞻性的方法吗?

Windows系统调用必须使用宽字符串,否则它们将在旧代码页中进行解释。对于程序中的一般字符串,使用宽字符串(与系统调用和MFC兼容)或UTF-8(与数据文件兼容,如果我们这样做)是否更好?

我们如何才能最大限度地降低UTF-8字符串被解释为遗留代码页的风险?我们过去曾遇到过海外用户的跨代码页面问题,离开这是我们转向完整Unicode的动机之一。

5 个答案:

答案 0 :(得分:2)

不幸的是,Windows中的情况有点难看。尽管在内部对Unicode进行了标准化,但在许多情况下仍然使用当前代码页来解释文本文件。

UTF-8是文件的理想选择,因为它允许在使用不同语言的Windows系统以及Linux及其亲属之间交换数据。您可以通过在文件的开头放置Byte order mark (BOM)来增加正确解释UTF-8文件的机会。它不是一个完美的解决方案;并非所有程序都能识别它,这违反了Unicode标准的建议。

Windows API使用UTF-16作为其Unicode接口。除非你喜欢逆潮流,否则我会坚持使用它来进行内部程序使用。

答案 1 :(得分:2)

在应用程序中,您有两个基本模型:

  • 在整个应用程序中使用UTF-16。
  • 在整个过程中使用UTF-8字符串,并在Win32 API / MFC / ... call
  • 转换为/到UTF-16

如果要大量使用不支持UTF-16的库,首先可能会出现问题。我从来没有发现这在实践中是一个问题。有些人会告诉你,你是愚蠢的,你的产品注定只是因为你使用的是UTF-16,但我从来没有发现 在实践中也是一个问题。

如果你屈服于同伴压力,或者依赖于现有的以UTF-8为中心的代码,那么在为CString转换成字符串的字符串使用自定义包装类时,可以简化内部使用UTF-8,以及一些辅助类处理[out] CString * / CString &)。对于非MFC非CString代码,std::vector<TCHAR>将是一个很好的表示。该包装器当然不应该隐含地转换为char *或wchar_t *。


您读写的文件

只要它们是“您的”应用程序文件,您就可以随心所欲。实际上,使用不透明(二进制)格式可能会使您完全脱离用户问题。只是保持一致。

当您开始处理来自其他应用程序的文件时会出现问题,或者可能希望用户使用其他应用程序编辑应用程序的文本文件。这是它开始变得黯淡的地方。由于UTF-8支持多年来一直非常有限,许多工具无法很好地应对。其他程序确实正确识别和解释UTF-8,但未能跳过任何BOM标记。

尽管如此,UTF-8仍然是“未来的安全赌注”。即使它是更多的前期开发,我强烈建议将它用于共享文件。


我们的解决方案,经过一些来回,如下:

阅读文本文件,默认算法为:

  • 探测BOM。如果存在,请依赖BOM(但当然跳过它)
  • 探测有效的UTF-16(我们甚至支持LE / BE,但不太可能出现BE)。
  • 仅探测ASCII(所有字节<= 127)。如果是,则解释为ASCII
  • 探测UTF-8。如果正文是有效的UTF-8,则读为UTF-8
  • 否则回退到当前代码页

UTF-8是专门设计的,因此任何其他编码实际上都是有效的UTF-8非常低。这使得最后两步的顺序相当安全。

编写文本文件,我们使用没有BOM的UTF-8。通过对我们使用的外部工具的简短信息调查,这是最安全的选择。

基于此,我们还包含了一个实用程序,以避免我们的开发人员和用户检测到非UTF-8文本文件并将其转换为UTF-8。

答案 2 :(得分:0)

我同意@DavidHeffernan的API,我还建议完全切换到Unicode(我们深呼吸并为我们的所有应用程序做了这一点,它是一次性的努力,在长期内得到回报术语)

答案 3 :(得分:0)

正如Mark Ransom已经回答的那样,正如David Heffernan和我已经评论过的那样,UTF-16是Windows程序内部的实用选择,而UTF-8是外部表示的一个很好的选择(交互式控制台除外) i / o,但这不是一个问题。)

由于您要从遗留代码转换而来,我会关注可重用性

可以通过不直接使用wchar_t直接使用潜在的独立于平台的可重复使用部件来实现可重复使用,而是例如类型Syschar有条件地定义为

enum Syschar: wchar_t {};    // For Windows, implying UTF-16

enum Syschar: char {};       // For Linux-land, implying UTF-8

使用enum代替struct可确保您可以使用该类型来专门化std::basic_string(当您定义正确的std::char_traits时),即使其实现使用了union用于短缓冲区优化。

正如大卫·惠勒所说,“计算机科学中的所有问题都可以通过另一层次的间接解决” - 这就是他们中的一个。

答案 4 :(得分:0)

  

UTF-8是保存数据文件的最具前瞻性的方法吗?

没有理由使用其他任何东西。

  

Windows系统调用必须使用宽字符串,否则它们将在旧代码页中解释。

您还可以使用带有UTF-8字符串的填充程序来封装Win32 API调用,并在调用UTF-16本机API之前对其进行转换。

  

对于程序中的常规字符串,使用宽字符串(与系统调用和MFC兼容)或UTF-8(与数据文件兼容,如果我们这样做)是否更好?

这真的取决于。您不希望在代码中分散转化,因为这样更有可能导致错过转化。

如果程序具有复杂的内部逻辑,那么希望您已经组织它,以便输入/输出代码和与系统API交互的代码都是相当本地化的,您可以选择以下任一路径:将转换置于API使用或对IO操作进行转换。如果系统API使用和IO尚未本地化,那么首先要修复它。

如果程序的逻辑非常简单,您不需要本地化其中一个,那么将转换放在更本地化的任何一个上。您还可以重构程序,使其中一个或另一个本地化,以简化转换。

  

我们如何才能最大限度地降低UTF-8字符串被解释为遗留代码页的风险?我们过去曾遇到过海外用户的跨代码页面问题,离开这是我们转向完整Unicode的动机之一。

建立一致的标准并加以执行。要求所有非wchar_t字符串都是UTF-8,并且不要使用任何使用旧编码的第一方或第三方API。如果您的工具链允许您禁用API(例如,通过“已弃用的&#39;”属性),那么在您查找并删除其用法时,请对API执行此操作。确保开发人员都了解字符串编码,并确保代码审查人员注意编码错误。