【问题标题】:Standard way in C11 and C++11 to convert UTF-8?C11 和 C++11 中转换 UTF-8 的标准方法?
【发布时间】:2013-10-29 03:36:28
【问题描述】:

C11 和 C++11 都引入了 uchar.h/cuchar 标头,将 char16_tchar32_t 明确定义为 16 位和 32 位宽字符,添加了用于编写字符串的文字语法 u""U""使用这些字符类型,以及告诉您它们是否对应于 UTF-16 和 UTF-32 代码单元的宏 __STDC_UTF_16____STDC_UTF_32__。这有助于消除关于 wchar_t 的歧义,在某些平台上是 16 位,通常用于保存 UTF-16 代码单元,而在某些平台上是 32 位,通常用于保存 UTF-32 代码单元;假设现在设置了这些宏,您现在可以编写引用 UTF-16 和 UTF-32 的可移植、明确的代码。 __STDC_ISO_10646__ 也可以用作代理来确定wchar_t 是否能够保存 UTF-32 值;如果不能,您不一定能假定它拥有 UTF-16,但它可能是一个足够接近的近似值,可以移植。

他们还添加了函数mbrtoc16mbrtoc32c16rtombc32rtomb,用于在多字节字符和这些类型之间进行转换。在这些和现有的mbstowcs 系列函数之间,可以在 UTF-16、UTF-32、平台多字节字符集和平台宽字符集之间进行可移植的转换(尽管不一定无损,除非平台定义了多字节和宽字符集是 UTF;特别是,这些函数在 Windows 上似乎毫无用处,因为语言环境定义的多字节编码不允许每个字符使用超过两个字节)。

此外,他们添加了 u8"" 语法来编写文字 UTF-8 编码字符串。由于 UTF-8 是一种与处理char *std::string 的大多数函数兼容的编码,因此这是最有用的新增功能之一。

但是,他们似乎没有添加任何方法来在 UTF-8、UTF-16 和 UTF-32 之间进行可移植转换。 mbtoc16 和相关函数在实现定义的多字节编码和 UTF-16 或 32 之间进行转换;但你不能依赖这是 UTF-8。在类 Unix 平台上,它依赖于语言环境,其中许多默认情况下在其语言环境中使用 UTF-8,即使它不是默认设置,您至少可以将语言环境设置为 UTF-8 语言环境以了解“多字节”表示 UTF-8。但是,在 Windows 上,您 explicitly can't use UTF-8 or any other encoding that requires more than two bytes for the locale

我只是遗漏了什么,还是 UTF-8 字符串类型没有伴随任何方式将其转换为其他类型的字符串:平台定义的多字节、平台定义的宽字符、UTF-16 或 UTF-32?甚至无法判断您的系统多字节编码是否为 UTF-8?是否有任何理由不包括这种支持(具体来说,我正在寻找 C 或 C++ 标准委员会的实际书面理由或讨论,而不仅仅是猜测)?是否正在做任何工作来改善这种情况?以后有可能改进吗?

或者,如果您想以可移植的方式支持 UTF-8、编写自己的实现、引入库依赖项或使用特定于平台的函数(如 iconvMultiByteToWideChar),或者,这是当前最好的解决方案?

【问题讨论】:

  • 请注意,这个问题与WChars, Encodings, Standards and Portability 非常相似,但我更感兴趣的是标准委员会的决定背后的推理,以及在以实际可行的方式标准化这一方面是否取得了进展,而不是“现在最好的方法是什么”。
  • "__STDC_ISO_10646__ 也可以用作代理来确定 wchar_t 是否能够保存 UTF-32 值;"没有。例如,OS X 没有定义这个,但使用 UTF-32 来表示 xx_XX.UTF-8 语言环境。它没有定义宏的原因是因为对于非 .UTF-8 语言环境,它可能使用非 UTF-32 编码。如果您想知道使用 UTF-32 的语言环境,您只需了解特定于该语言环境的信息。如果您想知道是否可以将 wchar_t 用于您自己的 UTF-32 数据和例程,那么您只需要确保 sizeof(wchar_t)*CHAR_BIT >= 21.
  • @bames53 叹息,你是对的。看来连这个都靠不住了。所以我想知道的是:为什么这不是标准化的?编写一个实际上允许您编写涉及 Unicode 的实际可移植代码的标准有什么障碍?现在,这个标准几乎没用。您需要分别为每个平台编写代码。这是他们实际尝试过但失败的事情,还是只是没有人对在 C 中标准化一组实际有用的 Unicode 例程特别感兴趣?
  • 我想最大的问题之一是每个平台都已经有了某种处理方式,而标准化某些东西会与现有的一种或另一种实现发生冲突。避免这种情况的唯一方法可能是标准化一个与现有标准功能无关的 Unicode 库。
  • 这意味着,例如,fopen() 的新版本。这是因为要可移植地使用 UTF-8,必须指定此类库组件采用什么编码,目前还没有这样做。在某些平台上 fopen 采用系统语言环境多字节编码,在某些平台上采用任意字节序列,在某些平台上采用 UTF-8 而与语言环境无关。

标签: c++11 unicode utf-8 character-encoding c11


【解决方案1】:

听起来您正在寻找std::codecvt 类型。有关用法,请参见该页面上的示例。

【讨论】:

  • 啊,这回答了 C++11 的问题。我仍然对C11很好奇。我可能会将我的问题更新为关于 C11,但由于 Microsoft 已明确拒绝支持 C89 以外的任何内容,因此询问有关 Windows 可移植性的问题可能是徒劳的。有趣的是,正如您在该页面底部的图表中看到的那样,对于某些转换,您可以使用std::codecvt,对于某些您必须使用 C 样式的转换函数,而有些转换不直接尽管您可以将它们组合在一起,但它们仍然存在。
  • 另请注意,标准 codecvts 仅提供 UTF-8 和 UTF-16、UCS-2 或 UTF-32 之间的转换,而不提供 UTF-8 和平台字符集之间的转换。为此,您需要两次转换,例如c32rtomb
  • @R.MartinhoFernandes 是的,这有点奇怪(正如我所指出的;其中一些不直接存在但可以组合)。你知道为什么有些转换是在 C 风格的 API 中指定的,有些是在 C++ 中指定的,而有些则被遗漏了吗?这一切似乎都是临时性的。
  • @BrianCampbell C 指定了他们自己关心的位。 C++ 指定了他们自己关心的位。然后,C++ 还采用了 C 在默认情况下指定的内容。这些不能一起使用。
  • @BrianCampbell 我不知道决策过程是如何进行的,但是通过查看所提供的功能以及如何提供的功能,我的印象是,整个事情是在非常非常临时的情况下完成的方式,可能只是匆忙。与委员会有关的人似乎很少关心和/或对主题有足够的了解,这并没有带来太大的进展。
猜你喜欢
  • 2011-05-03
  • 1970-01-01
  • 2014-03-05
  • 2014-02-05
  • 2012-06-11
  • 1970-01-01
  • 2015-01-14
  • 2020-11-13
  • 2015-07-21
相关资源
最近更新 更多