【问题标题】:Convert a `char *` to UTF-8 in C, or when using xmlwriter?在 C 中或在使用 xmlwriter 时将 `char *` 转换为 UTF-8?
【发布时间】:2019-07-10 16:42:56
【问题描述】:

我正在使用libxml/xmlwriter 在程序中生成 XML 文件。

const char *s = someCharactersFromSomewhere();
xmlTextWriterWriteAttribute (writer, _xml ("value"), _xml (s));

一般来说,我对s 的内容没有太多控制权,所以我不能保证它在UTF-8 中的格式是正确的。大多数情况下是这样,但如果不是,生成的 XML 格式将是错误的。

我想找到一种将s 转换为有效UTF-8 的方法,将s 中的任何无效字符序列替换为转义符或删除。

或者,如果有 xmlTextWriterWriteAttribute 的替代方案,或者我可以在初始化 XML 写入器时传入一些选项,这样它就可以保证它总是会写入有效的 UTF-8,那就更好了。

还有一点要提的是,该解决方案必须同时适用于 Linux 和 OSX。理想情况下,尽可能少地编写我自己的代码! :P

【问题讨论】:

  • 如果字符串是 UTF-8 且可能包含无效字节,那么在迭代代码点之前,我发现来自 ICU 的 U8_NEXT_OR_FFFD() 很有用。
  • This 和以下功能似乎相关——但您需要测试自己是否可以帮助您...

标签: c utf-8 libxml2


【解决方案1】:

如果字符串以 ASCII 编码,那么它将始终是有效的 UTF-8 字符串。 这是因为 UTF-8 向后兼容 ASCII 编码。

参见维基百科的第二段here

Windows 主要使用 UTF-16,这意味着您必须先将 UTF-16 转换为 UTF-8,然后才能将字符串传递给 XML 库。

【讨论】:

  • Windows:不一定。如果您启用了 unicode 构建并使用宽字符串 API,是的,如果没有,它仍然使用区域编码(如 CP1252)...
  • 不幸的是,在这种情况下,字符串不是有效的 ASCII(这就是为什么它也不是有效的 UTF-8)。因此问题。
  • 为了帮助你,我必须知道你从哪里得到字符串。
  • 好吧,假设 ASCII 字符集的代码点在值上与相同字符的 ascii 代码匹配。 Windows 不使用 utf-16 编码。它使用代码页,所有代码页都基于一字节字符集。主要是code page 1250 (iso-8859-1) 和437 (ibm charset) 最近才采用unicode,所以最近98%的软件还在用codepages。
  • 您需要编写一些特定于平台的代码并使用一些本机函数来查找文本的编码。如果不联系数据源,就无法知道文本是如何编码的。一旦你发现字符串使用什么编码,你可以使用一些库来为你做转换。
【解决方案2】:

如果您有 8 位 ascii 输入,那么您可以简单地将任何大于 127 的字符代码作为垃圾。

如果你有一些不可靠的 UTF-8,它很容易解析,但你生成的 Widechar 符号编号可能超出 unicode 范围。您可以使用mbrlen() 单独验证每个字符。

我正在使用无符号字符来描述这一点。如果您必须使用有符号字符,则 >128 表示

最简单的:

Until the null byte
 1 If the next byte is 0, then end the loop
 2 If the next byte is < 128 then it is ascii, so keep it
 3 If the next byte is >=128 < 128+64 it is invalid - discard it
 4 If the next byte is >= 128+64 then it is probably a proper UTF-8 lead byte
   call size_t mbrlen(const char *s, size_t n, mbstate_t *ps);
   to see how many bytes to keep 
   if mbrlen says the code is bad (either the lead byte or the trail bytes),
     skip 1 byte. Rule 3 will skip the rest.

即使是更简单的逻辑也只是重复调用 mbrlen,因为它可以接受低 ascii 范围。

您可以假设文件的所有“家具”(例如 xml >/ 符号、空格、引号和换行符)不会被此编辑更改,因为它们都是有效的 7 位 ascii 代码。

【讨论】:

  • If the next byte is &gt;= 128+64 then it is a proper UTF-8 introducer 并不完全正确。只有192..247 范围内的字节值对“介绍人”有效,正如您所说的那样(大多数人更可能将其称为“引导字节”)。
  • 是的,“铅字节”很好。这取决于我猜想的有效 utf 编码是什么意思——给它更多的尾随字节只会产生更多超出范围的值。好的,我将其更改为“可能有效”。如果 mbrlen() 超出范围,它将失败。
【解决方案3】:

char 是单字节字符,而 UTF 码位范围从 00x10FFFFF,那么如何仅用一个字节表示 UTF 字符?

首先你需要一个wchar_t 字符。这些与普通printf(3) 例程的wprintf(3) 版本一起使用。如果您对此进行深入研究,您会发现根据您的setlocale(3) 设置,将您的UTF 代码点映射到有效的UTF-8 编码是直截了当的。查看参考的手册页,您就会了解您面临的任务。

C 标准中完全支持宽字符集...但您必须通过国际化库和可用的语言环境来使用它。

【讨论】:

    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 2012-01-08
    • 2011-04-18
    • 2023-03-19
    • 1970-01-01
    • 2019-11-29
    • 2012-06-12
    • 2019-05-15
    相关资源
    最近更新 更多