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

问题描述 投票:0回答:6

我们有一套为ASCII字符集开发的应用程序。现在,我们正试图在冰岛安装它,但遇到了冰岛字符被搞砸的问题。

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

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

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

使用的操作系统是Windows和Linux。我们使用 std::string 和普通的 C 字符串。 (不要让我为任何设计决策辩护。我只是想帮助解决这个问题。)


以下是建议的清单:

c++ unicode utf-8 globalization
6个回答
10
投票

在大多数情况下,保持 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 代码页。


1
投票

注意完整的 unicode 不适合 16 位字符;所以要么使用 32 位字符,要么使用可变宽度编码(UTF-8 是最流行的)。


1
投票

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


0
投票

冰岛语使用 ISO Latin 1,所以八位应该足够了。我们需要更多细节来弄清楚发生了什么。


0
投票

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

你不应该对 UTF-8 导致问题感到惊讶; UTF-8 将非 ASCII 字符(例如带重音的拉丁字符、thorn、eth 等)编码为每个两个字节。

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


-1
投票

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

还使用可识别 Unicode 的字符串函数(请参阅文档)。如果某些东西操纵宽字符或字符串,它通常会意识到它们是宽的。

© www.soinside.com 2019 - 2024. All rights reserved.