如何从十六进制转换为 Unicode 代码点?

How do I convert from Hex to a Unicode code point?

我有一个指向以 UTF8 编码的字节流的指针。我正在尝试将此字节流发布为 JSON 兼容字符串。

在我按下 em 破折号之前,它工作正常。此时我程序的输出开始出现垃圾。

我使用 snprintf 来完成工作:

if (nUTF8CodePoints == 2)
{
    DebugLog(@"2 Unicode code points");
    snprintf( myEscapedUnicode, 8, "\u%2x%2x",*cur,*(cur+1));
}
else if (nUTF8CodePoints == 3)
{
    DebugLog(@"3 Unicode code points");
    snprintf( myEscapedUnicode, 8, "\u%2x%2x%2x",*cur,*(cur+1),*(cur+2));
}
else if (nUTF8CodePoints == 4)
{
    DebugLog(@"4 Unicode code points");
    snprintf( myEscapedUnicode, 8, "\u%2x%2x%2x%2x",*cur,*(cur+1),*(cur+2),*(cur+3));
}

此代码在我预期的 U+2014 处给出了 \ue2809。现在我很困惑。我认为 U+XXXX 意味着 XXXX 应该是十六进制的。然而,十六进制表示法给我的 6 位数字与预期的 4 位数字不同。我应该如何将其编码为预期的 JSON 兼容 UTF-8?

有些东西告诉我我很接近,但不是雪茄。例如, utf8-chartable.de em dash entry 同意我的看法,这是有区别的。尽管如此,我还是不太明白它是什么,也不确定如何让 C 打印它。

  U+2014    —   e2 80 94    EM DASH

那么如何将这 3 个字节 (e2 80 94) 打印为 U+2014? XXXX 在这个 U+2014 中是什么意思?我以为应该是十六进制。

据我了解,JSON 允许(有例外)按原样包含 UTF-8 编码的文本。因此,首先,我认为您根本不需要特殊对待 Unicode 字符,或尝试将它们变成 \uXXXX 转义序列。

如果你确实想发出一个 \uXXXX 序列,你将不得不从 UTF-8 转换回“纯”Unicode 字符(或者,正式地,更像 UTF-16 ).一种方法是使用 mbtowc 函数——至少,如果您的 C 库符合要求,并且您已经正确设置了语言环境。我认为您应该可以像这样使用它:

setlocale(LC_CTYPE, "UTF-8")

wchar_t wc;
mbtowc(&wc, cur, nUTF8CodePoints);
snprintf(myEscapedUnicode, 8, "\u%04x", wc);

唯一的问题是不适合 16 位的字符,或者换句话说,基本多语言平面 (BMP) 之外的字符。虽然 UTF-8 可以很好地处理这些,但据我所知,在 JSON 中,它们 必须 编码为代理对,使用 \u 表示法。 (我从 Wikipedia 那里学到了这一点;我在这里没有声称任何 JSON 专业知识。)

到目前为止,我已经在自己的 JSON 工作中回避了这个要求。我会冒险并猜测它看起来像这样(请参阅维基百科中的 this description of low and high surrogates):

if(w > 0xffff) {
    unsigned int lo = (w - 0x10000) & 0x3ff;
    unsigned int hi = ((w - 0x10000) >> 10) & 0x3ff;
    snprintf(myEscapedUnicode, 12, "\u%04x\u%04x", hi + 0xD800, lo + 0xDC00);
}

请注意,这将在 myEscapedUnicode 中占用超过 8 个字节。