我们正在将Windows代码从传统字符集转换为Unicode。 我们的GUI代码使用MFC,但是我们也有很多非GUI模块将被合并到非MFC环境中。
UTF-8是保存数据文件最有前途的方法吗?
Windows系统调用必须使用宽字符string,否则将在旧版代码页中进行解释。 对程序中的一般string使用宽string(兼容系统调用和MFC)还是UTF-8(如果我们这样去使用兼容数据文件)是更好的方法吗?
我们如何才能将UTF-8string解释为遗留代码页的风险降至最低? 过去,海外用户遇到了跨代码页面问题,摆脱这种困境是我们转向全面Unicode的动机之一。
不幸的是,Windows中的情况很糟糕。 尽管在内部对Unicode进行了标准化,但在许多情况下仍然使用当前代码页来解释文本文件。
对于文件来说,UTF-8是一个不错的选择,因为它允许在使用不同语言的Windows系统,Linux及其亲属之间交换数据。 您可以通过在文件的开始处添加字节顺序标记(BOM)来增加正确解释UTF-8文件的机会。 这不是一个完美的解决方案; 并不是所有的程序都能识别它,而且它违背了Unicode标准的建议。
Windows API使用UTF-16作为其Unicode接口。 除非你喜欢逆潮流游泳,否则我会坚持使用内部程序。
在应用程序内部 ,您有两个基本模型:
如果您要大量使用不支持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是“未来的安全赌注”。 即使是更直接的开发,我强烈建议使用它共享文件。
我们的解决方案 ,经过一段时间后,如下:
读取文本文件 ,默认的算法是:
UTF-8是专门设计的,所以任何其他的编码实际上是有效的,UTF-8是非常低的。 这使得最后两个步骤的顺序相当安全。
编写文本文件 ,我们使用没有BOM的UTF-8。 从我们使用的外部工具的简短信息调查来看,这是最安全的选择。
基于此,我们还包括一个实用程序,以免我们的开发人员和用户检测并将非UTF-8文本文件转换为UTF-8。
我会同意@DavidHeffernan的API,我也建议彻底转换到Unicode(我们深深地吸了一口气,为我们的所有应用程序做了这样的工作,这是长期以来的一次性努力)
正如David Heffernan和我已经评论过的,Mark Ransom已经回答说,UTF-16是Windows程序内部的实际选择,而UTF-8是外部表示的非常好的选择(除了交互式控制台I / O ,但这不是什么大问题)。
既然你是从遗留的代码转换,我想然后集中于可重用性 。
潜在的独立于平台的可重用部分可以通过不直接盲目使用wchar_t
而实现真正的可重用,而是例如一个有条件地定义为
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
),即使其实现使用联合进行短缓冲区优化。
正如戴维·惠勒(David Wheeler)所言:“计算机科学中的所有问题都可以通过另一个层面的间接方式来解决 – 这就是他们之一。
UTF-8是保存数据文件最有前途的方法吗?
真的没有理由使用其他任何东西。
Windows系统调用必须使用宽字符字符串,否则将在旧版代码页中进行解释。
您还可以将Win32 API调用与采用UTF-8字符串的垫片包装在一起,并在调用UTF-16本地API之前对其进行转换。
对程序中的一般字符串使用宽字符串(兼容系统调用和MFC)还是UTF-8(如果我们这样去使用兼容数据文件)是更好的方法吗?
这真的取决于。 您不希望在整个代码中分散转化,因为这更可能导致转化错失。
如果程序有复杂的内部逻辑,那么希望你已经组织好了,这样输入/输出代码和与系统API交互的代码都是非常本地化的,你可以选择任一路径:put转换API使用或put IO操作转换。 如果系统API使用情况和IO尚未本地化,那么从修复这个问题开始。
如果程序的逻辑足够简单,你不需要本地化一个或另一个,然后把转换的任何一个更本地化。 您也可以重构程序,使其中一个或另一个本地化,以减轻转换。
我们如何才能将UTF-8字符串解释为遗留代码页的风险降至最低? 过去,海外用户遇到了跨代码页面问题,摆脱这种困境是我们转向全面Unicode的动机之一。
建立一致的标准并加以执行。 要求所有非wchar_t字符串为UTF-8,不要使用任何使用传统编码的第一方或第三方API。 如果您的工具链允许您禁用API(例如,通过“不推荐使用”的属性),那么在您找到并移除其用法时,对API执行此操作。 确保开发人员都了解字符串编码,并确保代码审查人员注意编码错误。