【问题标题】:Converting a UTF-8 text to wchar_t将 UTF-8 文本转换为 wchar_t
【发布时间】:2014-02-02 22:48:49
【问题描述】:

我知道这个问题已经在这里被问过很多次了,我确实阅读了一些答案,但是有一些建议的解决方案,我试图找出最好的解决方案。

我正在编写一个 C99 应用程序,它基本上接收以 UTF-8 编码的 XML 文本。

它的部分工作是复制和操作那个字符串(找到一个 substr,cat it,ex..)

由于我现在不想使用外部非标准库,因此我尝试使用 wchar_t 来实现它。

目前,我使用 mbstowcs 将其转换为 wchar_t 以便于操作,并且对于某些输入,我尝试使用不同的语言 - 它运行良好。

问题是,我确实读过一些人对 UTF-8 和 mbstowcs 有一些问题,所以我想知道这种使用是否被允许/可接受。

我面临的其他选择是使用带有 WCHAR_T 参数的 iconv。事情是,我在一个平台(不是 PC)上工作,它的语言环境非常非常仅限于 ANSI C 语言环境。那个怎么样?

我也遇到过一些非常流行的 C++ 库。但我仅限于 C99 实现。

另外,我将在另一个平台上编译此代码,wchar_t 的 sizeof 不同(2 字节与我的机器上的 4 字节)。我该如何克服呢?使用固定大小的字符容器?但是,我应该改用哪些操作函数?

很高兴听到一些想法。谢谢。

【问题讨论】:

  • 遇到困难和问题,我保证。 UTF-8 是一种编码,wchar_t 是一种存储细节,两者无关。 wchar_t 只是让处理 UTF-16 稍微容易一些,但是代理对呢? UTF-8 中的多字节单字符?
  • 谢谢。你能解释一下吗?
  • mbstowcs 有什么问题?
  • @Johnnyguitar 下面发布的答案更好地解释了我的观点。
  • @Dai:UTF-8 中不存在“代理对”。它们是 UTF-16 的编码细节。

标签: c utf-8 wchar-t


【解决方案1】:

C 没有定义charwchar_t 类型的编码是什么,标准库只规定了一些在两者之间转换的函数而没有说明如何转换。如果char 的实现相关编码不是UTF-8,那么mbstowcs 将导致数据损坏。

the rationale for the C99 standard中所述:

但是,这五个功能通常过于严格和原始,无法开发可移植的国际化程序来管理字符。

...

C90 故意选择不发明更完整的多字节和宽字符库,而是选择等待随着 C 社区获得更多宽字符经验而自然发展。

来自here

因此,如果您的 chars 中有 UTF-8 数据,则没有标准的 API 方法可以将其转换为 wchar_ts。

在我看来,wchar_t 除非必要,否则通常应该避免使用 - 例如,如果您使用 WIN32 API,则可能需要它。我不相信它会简化字符串操作。 wchar_t 在 Windows 上始终是 UTF-16LE,因此您可能仍然需要多个 wchar_t 来表示单个 Unicode 代码点。

我建议您调查ICU project - 至少从教育的角度来看。

【讨论】:

  • 非常感谢!我挖掘了一些关于 ICU 的信息,但我找不到任何有用的例子。我应该只使用 ICU 来转换字符串,还是它也有任何字符串操作功能?
  • 我建议你从the ICU API开始,看看它是否满足你的需求。
  • 据我了解,为了在 ICU 上的 UTF-8 字符串上很好地使用字符串操作函数(如此处所述link),我必须将我的字符串转换为 UTF-16。问题是,如果我的某些字符串包含在 UTF-8 中使用 3-4 个字节的字母,它们如何“翻译”为使用 1-2 个字节的 UTF-16?
  • 看来您必须“手动”将 utf-8 编码数据转换为 utf-16。你可以这样做,当然。您必须检测单字节以及 2,3 和 4 字节序列的 utf-8 字节流。我希望你知道如何解码代码点。对于任何作为代理的代码点,丢弃它,这是非法的。对于所有低于 0xFFFF 的代码点,您只需将值设置到您的 wchar 上(应为 16 位宽)。对于高于 0xFFFF 的代码点,您必须创建一个代理对。如果您的 wchar 是 32 位宽,只需从 utf-8 转码为 utf-32。
  • 顺便说一下,UTF-16 不使用 1-2 个字节,它使用单词。代理对实际上是字流中的一个双字,它编码高于 0xFFFF 的代码点。在代理对中,高代理必须先出现,然后是低代理。反之亦然是非法的,如果代理人不成对出现,那么这些代理人就是孤儿代理人。
【解决方案2】:

另外,我会在另一个平台上编译这段代码, wchar_t 的 sizeof 不同(在我的机器上是 2 个字节与 4 个字节)。 我该如何克服呢?使用固定大小的字符容器?

你可以用这样的条件类型定义来做到这一点:

#if defined(__STDC_UTF_16__)
   typedef _Char16_t CHAR16;
#elif defined(_WIN32)
   typedef wchar_t   CHAR16;
#else
   typedef uint16_t  CHAR16;
#endif

#if defined(__STDC_UTF_32__)
   typedef _Char32_t CHAR32;
#elif defined(__STDC_ISO_10646__)
   typedef wchar_t   CHAR32;
#else
   typedef uint32_t  CHAR32;
#endif

这将定义 typedefs CHAR16CHAR32 以使用新的 C++11 字符类型(如果可用),否则尽可能使用 wchar_t 和固定宽度的无符号整数。

【讨论】:

    猜你喜欢
    • 2011-12-18
    • 2018-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 2015-09-21
    相关资源
    最近更新 更多