【问题标题】:using unicode in a C++ program在 C++ 程序中使用 unicode
【发布时间】:2016-01-04 19:37:26
【问题描述】:

我希望在我的文件同步器应用程序中正确处理带有 Unicode 字符的字符串,但我不知道这种编码是如何工作的?

在 unicode 字符串中,我可以看到 unicode char 具有这种形式: "\uxxxx" 其中 xs 是数字,普通 C 或 C++ 程序如何解释这种 char ? (为什么'\'后面有'u'?有什么作用?)

在互联网上,我看到使用“宽字符串或 wchar_t ?? 那么,处理 unicode 字符的合适对象是什么?在 rapidJson(支持 Unicode、UTF-8、UTF-16、UTF-32)中,我们可以使用 const char* 来存储可能具有“宽字符”但这些字符需要超过一个字节才能表示的 JSOn。 . 我不明白...

这是我暂时找到的那种临时安排(unicode->utf8?ascii?, listFolder is a std::string):

boost::replace_all(listFolder, "\\u00e0", "à");
boost::replace_all(listFolder, "\\u00e2", "â");
boost::replace_all(listFolder, "\\u00e4", "ä");
...

【问题讨论】:

  • 只是“具有 Unicode 字符”并不是一个非常精确的定义。你打算和他们做点什么吗?如果只需要存储和转发字符串,可以将 Unicode 字符串视为不透明的字节字符串,长度以字节为单位。

标签: c++ boost unicode


【解决方案1】:

在 C++ 中处理 Unicode 字符串的合适对象是 icu::UnicodeString(检查侧栏中的“API References, ICU4C”),至少如果你想真正处理 Unicode 字符串(而不是只是将它们从应用程序的一个点传递到另一个点)。

wchar_t 是处理国际字符集的早期尝试,结果证明是失败的,因为一旦 Unicode 扩展到代码点 0x10000 之外,Microsoft 将 wchar_t 定义为两个字节就变得不够了。 Linux 将wchar_t 定义为四个字节,但不一致使得它(及其派生的std::wstring)对于可移植编程毫无用处。

TCHAR 是 Microsoft 定义的,默认情况下解析为 char,如果定义了 UNICODE,则解析为 WCHAR,而 WCHAR 反过来又是 wchar_t 在间接级别后面......是的。

C++11 为我们带来了char16_tchar32_t 以及相应的字符串类,但这些仍然是basic_string<> 的实例,因此也有它们的缺点,例如当尝试使用具有多个替换字符的大写/小写字符时(例如,德语 ß 需要扩展为大写的 SS;标准库不能这样做)。

另一方面,重症监护室则全力以赴。例如,它提供标准字符串不提供的规范化和分解。


\uxxxx\UXXXXXXXX 是 unicode 字符转义。 xxxx 是一个 16 位的十六进制数字,表示 UCS-2 代码点,相当于Basic Multilingual Plane 中的 UTF-16 代码点

XXXXXXXX 是一个 32 位的十六进制数字,代表一个 UTF-32 代码点,可以是任何平面。

如何处理这些字符转义取决于它们出现的上下文(例如,窄/宽字符串),这使得它们不太完美。

C++11 引入了“正确的”Unicode 文字:

u8"..."总是const char[]UTF-8 编码

u"..."总是const uchar16_t[]UTF-16 编码

U"..."总是const uchar32_t[]UTF-32 编码

如果您在这三个之一中使用\uxxxx\UXXXXXXXX,则字符文字将始终扩展为正确的代码单元序列。


请注意,将 UTF-8 存储在 std::string 中是可能的,但很危险。您需要注意很多事情:.length() 不是字符串中的字符数。 .substr() 可能导致部分和无效序列。 .find_first_of() 将无法按预期工作。以此类推。

话虽如此,在我看来,UTF-8 是任何存储文本的唯一合理的编码选择。有一些情况可以将文本作为内存中的 UTF-16 处理(ICU 的方式),但在文件中,除了 UTF-8 之外不接受任何内容。它节省空间,与字节序无关,即使是完全不了解 Unicode 问题的软件也可以进行半理智的处理(请参阅上面的警告)。

【讨论】:

  • 非常有启发性和趣味性,例如,有了这个ICU,在Windows控制台中正确打印unicode字符很容易吗?用正确的名称保存文件?我的意思是操作系统和程序之间的交互会顺利吗?
  • @Aminos:如果您的应用程序在文本上执行“繁重的工作”,ICU 是“真实的”。如果您所做的只是将文件名从应用程序的一端传递到另一端,那么您会发现使用本机 API 为其函数接受的任何字符串类型都会更容易。 IIRC,WinAPI 想要/提供TCHAR[]std::wstring 的有趣组合,并且不清楚这是否意味着 UCS-2(即没有代理对)或完整的 UTF-16(包括代理对)。哦,cmd.exe 不支持 Unicode,也没有第三方库可以改变它...
  • @Aminos: 危险,因为std::basic_string< char > 将每个char 视为一个单独的字符,而 UTF-8 是一种 多字节 编码,每个字符包含 1 到 6 个字节.您不能在 UTF-8 std::string 中使用 .find_first_of( 'äåé' ),因为这些字符都不会被编码为单个字节。
  • 有一天,我必须为所有这些东西写一个非常好的总结,并将其添加到 C++ 常见问题解答中。问题是,Unicode 的主题大量...即使是 Joel Spolsky 出色的 article 也只是触及了表面,真的。
【解决方案2】:

在 unicode 字符串中,我可以看到 unicode char 具有这种形式: "\uxxxx" 其中 xs 是数字,普通 C 或 C++ 程序如何解释这种 char ? (为什么'\'后面有'u'?有什么作用?)

这是一个 unicode 字符转义序列。它将被解释为 unicode 字符。转义字符后的u 是语法的一部分,这也是它与其他转义序列的区别所在。阅读documentation了解更多信息。

那么,处理 unicode 字符的合适对象是什么?

  • char 用于 uft-8
  • char16_t 用于 utf-16
  • char32_t 用于 utf-32
  • wchar_t 的大小取决于平台,因此您不能对它适合哪种编码做出可移植的假设。

我们可以使用 const char* 来存储一个可以包含“宽字符”的 JSOn,但这些字符需要超过一个字节才能表示...

如果您的意思是可以将多字节 utf-8 字符存储在 char 字符串中,那么您是正确的。

这是我暂时找到的那种临时安排(unicode->utf8?ascii?, listFolder is a std::string)

您在那里尝试做的是将一些 unicode 字符替换为具有平台定义编码的字符。如果除了这些之外还有其他 unicode 字符,那么最终会得到一个混合编码的字符串。此外,在某些情况下,它可能会意外替换其他字节序列的一部分。我建议使用库来转换编码或对编码字符串进行任何其他操作。

【讨论】:

  • 您可以在char 字符串中存储 UTF-8。但是你不能正确处理它。
猜你喜欢
  • 2010-12-27
  • 1970-01-01
  • 1970-01-01
  • 2012-05-01
  • 2023-03-29
  • 2011-01-07
  • 2012-08-10
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多