我有一个带有utf8实体的字符串(我不确定我的名字是否正确):
std::string std = "u0418u043du0434u0435u043au0441";
如何将其转换为更具可读性的内容?我使用支持 C++11 的 g++,但是在挖掘 std::codecvt 手册几个小时后,我没有得到任何结果:
std::string std = "u0418u043du0434u0435u043au0441";
wstring_convert<codecvt_utf8_utf16<char16_t>,char16_t> convert;
string dest = convert.to_bytes(std);
返回以以下内容开头的噩梦堆栈跟踪:
error: no matching function for call to ‘std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>::to_bytes(std::string&)
我希望还有另一种方式。
首先,你对std::wstring_convert
的使用是倒退的。 您有一个 UTF-8 编码的std::string
,要将其转换为宽 Unicode 字符串。 您收到编译器错误,因为to_bytes()
不将std::string
作为输入。 它需要一个std::wstring_convert::wide_string
作为输入(这在您的情况下是std::u16string
,因为您在专业化中使用了char16_t
),因此您需要使用from_bytes()
而不是to_bytes()
:
std::string std = "u0418u043du0434u0435u043au0441";
std::wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t> convert;
std::u16string dest = convert.from_bytes(std);
话虽如此,JSON 规范的第 9 节指出:
9 字符串
字符串是用引号 (U+0022) 括起来的 Unicode 代码点序列。除必须转义的字符外,所有字符都可以放在引号内:引号 (U+0022)、反固线 (U+005C) 和控制字符 U+0000 到 U+001F。某些字符的转义序列表示形式为两个字符。
"
表示引号字符 (U+0022)。
\
表示反向固相线字符 (U+005C)。
/
表示固线字符 (U+002F)。
b
表示退格符 (U+0008)。
f
表示表单馈送字符 (U+000C)。
n
表示换行符 (U+000A)。
r
表示回车符 (U+000D)。
t
表示字符制表字符 (U+0009)。因此,例如,仅包含一个反向实线字符的字符串可以表示为"
\
"。任何代码点都可以表示为十六进制数。这种数字的含义由 ISO/IEC 10646 确定。如果代码点位于基本多语言平面(U+0000 到 U+FFFF)中,则可以表示为六个字符的序列:反向固相线,后跟小写字母
u
,后跟对代码点进行编码的四个十六进制数字。十六进制数字可以是数字(U+0030 到 U+0039)或大写A
到F
的十六进制字母(U+0041 到 U+0046)或小写(U+0061 到 U+0066)。因此,例如,仅包含一个反向固线字符的字符串可以表示为"u005C
"。以下四种情况都产生相同的结果:
"
u002F
">"
u002f
">"
/
">"
/
">为了转义不在基本多语言平面中的代码点,该字符表示为 12 个字符的序列,对 UTF-16 代理项对进行编码。例如,仅包含G谱号字符(U+1D11E)的字符串可以表示为"
uD834uDD1E
"。
原始 JSON 数据本身可以用 UTF-8(最常见的编码)、UTF-16 等进行编码。 但无论使用何种编码,字符序列"u0418u043du0434u0435u043au0441"
都表示 UTF-16 代码单元序列U+0418 U+043d U+0434 U+0435 U+043a U+0441
,即 Unicode 字符串"Индекс"
。
如果您使用实际的 JSON 解析器(例如 JSON for Modern C++、jsoncpp、RapidJSON 等),它将为您解析 UTF-16 代码单元值并返回可读的 Unicode 字符串。
但是,如果您手动处理 JSON 数据,则必须手动解码任何x
并uXXXX
转义序列。std::wstring_convert
不能为你做到这一点。 它只能将 JSON 从std::string
转换为std::wstring
/std:::u16string
,如果这使您可以更轻松地解析数据。 但是,您仍然必须单独分析 JSON 的内容。
之后,如果需要,您可以使用std::wstring_convert
将任何提取的std::wstring
/std::u16string
字符串转换回UTF-8以节省内存。
您看到的不是实体,而是代码点。您通过 Unicode 转义序列定义字符,编译器会自动将它们转换为 UTF-8。将其转换为 UTF-16 反之亦然的典型方法是:
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string ws2s(const std::wstring &wstr) {
std::string narrow = converter.to_bytes(wstr);
return narrow;
}
std::wstring s2ws(const std::string &str) {
std::wstring wide = converter.from_bytes(str);
return wide;
}
当然,您不能将原始字符串转换为另一个相同类型的字符串(std::string),因为它不能容纳此类字符。这就是为什么 UTF-16 代码首先由编译器转换为 UTF-8 的原因。