我们如何编写对UTF-8安全的代码?

时间:2020-03-06 14:43:53  来源:igfitidea点击:

我们有一组针对ASCII字符集开发的应用程序。现在,我们正在尝试将其安装在冰岛,并且遇到了冰岛字符搞砸的问题。

我们正在解决问题,但我想知道:是否有一个好的"指南"来编写专为8位字符设计的C ++代码,并且在将UTF-8数据提供给它时​​,它可以正常工作?

我不能指望每个人都能阅读整个Unicode标准,但是如果有一些更容易理解的东西,我想与团队分享,以便我们不再遇到这些问题。

重新编写所有使用wchar_t或者其他字符串表示形式的应用程序目前尚不可行。我还将注意到,这些应用程序通过网络与使用8位字符的服务器和设备进行通信,因此,即使我们在内部进行Unicode编码,我们在边界上仍然会遇到问题。在大多数情况下,这些应用程序只是传递数据。除了从一个地方复制到另一个地方,他们不会以任何其他方式"处理"文本。

使用的操作系统是Windows和Linux。我们使用std :: string和普通的C字符串。 (也不要要求我为任何设计决策辩护。我只是在尝试解决问题。)

以下是建议的清单:

  • 每个软件开发人员绝对必须绝对了解Unicode和字符集(没有任何借口!)
  • 适用于Unix / Linux的UTF-8和Unicode常见问题解答
  • Unicode HOWTO

解决方案

我们可能要使用宽字符(用wchar_t代替char和std :: wstring代替std :: string)。这不会自动解决100%的问题,但这是很好的第一步。

还请使用支持Unicode的字符串函数(请参阅文档)。如果某些东西操纵宽字符或者字符串,则通常会知道它们很宽。

这看起来像一个全面的快速指南:
http://www.cl.cam.ac.uk/~mgk25/unicode.html

请注意,完整的unicode不适用于16位字符。因此请使用32位字符或者可变宽度编码(UTF-8最为流行)。

冰岛语使用的是ISO Latin 1,因此八位就足够了。我们需要更多细节来了解正在发生的事情。

UTF-8的设计完全考虑了问题。我要注意的一件事是ASCII实际上是7位编码,因此,如果基础结构的任何部分将8位用于其他目的,则可能会有些棘手。

在大多数情况下,仅需进行8位清除即可。但是,我们必须注意,任何非ASCII字符都会拆分为多个字节,因此,如果要换行或者截断要显示的文本,则必须考虑这一点。

UTF-8的优点是,我们始终可以知道多字节字符的位置:如果设置了位7而复位了位6(字节为0x80-0xBF),则这是尾随字节,而如果位7和6为置位并复位5(0xC0-0xDF),这是一个前导字节,后跟一个字节;如果设置了7、6和5,并复位了4(0xE0-0xEF),则它是带有两个尾随字节的前导字节,依此类推。设置在最高有效位上的连续位数是组成字符的字节总数。那是:

110x xxxx =两字节字符
1110 xxxx =三字节字符
1111 0xxx =四字节字符
等等

冰岛字母全部包含在ISO 8859-1中,因此包含在Windows-1252中。如果这是控制台模式的应用程序,请注意该控制台使用IBM代码页,因此(取决于系统语言环境)它可能会显示在437、850或者861中。Windows不支持UTF-8. 我们必须转换为UTF-16并使用Unicode API。

如果它是控制台模式应用程序,则调用SetConsoleCP和SetConsoleOutputCP(指定代码页1252)将有助于解决问题。不幸的是,所选的控制台字体必须是支持代码页的字体,而且我看不到设置字体的方法。标准位图字体仅支持系统默认的OEM代码页。

我们可能想查看ICU。他们可能有可用的函数,这些函数使使用UTF-8字符串更容易。

可以使用8位字符集(Windows上为CP1252,* x为ISO 8859-1 aka Latin1)来支持冰岛语,如法语,德语和西欧大多数其他语言。这是Unicode发明之前的标准方法,并且仍然很普遍。正如我们所说的那样,我们有一个约束,我们不能重写应用程序以使用wchar,也不需要这样做。

我们不应该对UTF-8引起问题感到惊讶; UTF-8将非ASCII字符(例如重音拉丁字符,刺,eth等)编码为两个字节。

可以给出的唯一一般建议非常简单(理论上):
(1)确定系统中要支持的字符集(Unicode,Latin1,CP1252等)
(2)如果正在向我们提供以其他某种方式编码的数据(例如UTF-8),请在系统边界将其转码为标准格式(例如CP1252)
(3)如果我们需要提供以其他某种方式编码的数据,则...