Sob*_*oby 2 c++ unicode utf-16 cjk cpprest-sdk
我正在处理这个代码,它接收一个 cpprest sdk 响应,其中包含一个 base64_encoded 有效负载,它是一个 json。这是我的代码片段:
typedef std::wstring string_t; //defined in basic_types.h in cpprest lib
void demo() {
http_response response;
//code to handle respose ...
json::value output= response.extract_json();
string_t payload = output.at(L"payload").as_string();
vector<unsigned char> base64_encoded_payload = conversions::from_base64(payload);
std::string utf8_payload(base64_encoded_payload.begin(), base64_encoded_payload.end()); //in debugger I see the Japanese chars are garbled.
string_t utf16_payload = utf8_to_utf16(utf8_payload); //in debugger I see the Japanese chars are good here
//then I need to process the utf8_payload which is an xml.
//I have an API available to process the xml which takes an string
processXML(utf16_payload); //need to convert utf16_payload to a string here;
}
Run Code Online (Sandbox Code Playgroud)
我也试过这个,我看到 str 包含乱码!
#include <codecvt> // for codecvt_utf8_utf16
#include <locale> // for wstring_convert
#include <string> // for string, wstring
void wstr2str(void) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conversion;
std::wstring japanese = L"?? ??";
std::string str = conversion.to_bytes(japanese); //str is garbled:(
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:可以将包含日语字符的 utf8 转换为 std::string 而不会出现乱码吗?
更新:我获得了processXML()代码的访问权限并将输入参数类型更改为 std::wstring 并且它起作用了。我想在创建 xml 时,它正在将 std::string 转换为 wstring;然而,结果并不好!
void processXML(std::wstring xmlStrBuf) { //chaned xmlStrBuf to wstring and worked
// more code
CComBSTR xmlBuff = xmlStrBuf.c_str();
VARIANT_BOOL bSuccess = false;
xmlDoc->loadXML(xmlBuff, &bSuccess);
//more code
Run Code Online (Sandbox Code Playgroud)
}
感谢您的回答,当提到字符串只是一个存储时,他们很有帮助。
你在这里混淆了不同的概念。
贮存
这就是我们保存/存储/保存数据的方式。Astd::string是chars的集合,它们是bytes。Astd::wstring是一个集合wchar_ts,它们有时是 2 字节宽的值(但这不能保证!)。
编码
这就是数据的含义,以及应该如何解释它。一种std::string,一组字节,可以包含 UTF-8、UTF-16、UTF-32、ASCII、ShiftJIS、莫尔斯电码、JPEG、电影或我的 DNA(幸运字符串!)。
世界上有一些强大的公约在起作用。例如,在 Windows 上,一个std::wstring通常接受 a 来保存 UTF-16(因为两字节存储对此很方便,也因为 Windows API 就是这样做的)。
较新版本的 C++ 为我们提供了诸如std::u16_string和 之类的东西std::u32_string,它们仍然没有任何直接的编码概念,但打算分别用于 UTF-16 和 UTF-32,因为它们的名称使代码读者更容易理解这一意图. C++20 将引入std::u8_stringwhich 旨在表示 UTF-8 编码的字符串(否则或多或少像std::string)。
但这些只是约定俗成。没有关于类型std::string说“UTF-8”或任何其他东西。它不知道、不关心或强制执行任何编码。它只存储字节。
因此,您关于“将 UTF-8 转换为std::string”的问题没有任何意义;这就像问如何将道路改装成汽车。
“那我该怎么办?”
好吧,Base64 也不是编码。嗯,实际上,它完全是,但它是在字符串编码之上的一种编码。这是一种传输/转义/清理原始字节的方式,而不是一种描述以后如何解释它们的方式。通过要求 cpprest 从 Base64 转换,这只是改变了提供原始字节的方式。这就是为什么它给你 astd::vector<char>而不是 astd::string因为,虽然(如上所述)std::string不关心编码,我们有时使用 astd::vector<char>真的,正确地,完全说“这个集合没有任何特定的编码,所以请不要试图从约定或任何编码在这个用例中猜测;它只知道它是一堆字节”。这取决于意见。有些人仍然会使用 a std::string;cpprest 的作者决定不这样做。
关键是该函数的使用from_base64无法告诉我们有关您检索到的文本的编码的任何信息。为此,我们必须回到文本的文档。我们无法访问它,您也没有告诉我们任何有关它的信息。如果它只是一个 JSON 字符串,编码将归结为 cpprest JSON 库,因此您已经完成了。然而,事实并非如此:它是由创建 JSON 对象的人打包到 Base64 表示中的。同样,该信息不是您与我们共享的内容。
但是,根据您选择的变量名称,您正在查看的数据已经是 UTF-8。然后您尝试将其转换为 UTF-16,这与您所描述的您想要做的相反。
(同样,在你的第二个例子,你拍一个std::wstring是[大概]已经存储UTF-16感谢L"wide string literal",然后告诉计算机,它的UTF-8,并以“再”将其转换为UTF-16,然后提取原始字节转换为 a std::string。这些都没有意义。)
相反,为什么不只是字面意思processXML(utf8_payload);?
一般建议
编码可能非常复杂,尽管一旦您将头脑围绕所有这些抽象层的基本概念,处理起来就会容易得多。对于未来,对于这个问题,如果你想澄清它,你需要确保你是绝对清楚的,在你的数据“管道”的每个阶段,因为它从 A 地传输到 B 地,并得到从类型 C 转换为类型 D,以及其他任何关于在每个步骤中应该采用什么编码的问题。如果您想在其中一个步骤中更改编码,请这样做(尽管这种情况很少见!)。但是在编写任何代码之前,请确保您确定知道自己需要什么,否则您将陷入困境。
不过,最终您将开始检测可以提供帮助的模式。例如,如果您期待一些美味的非 ASCII 输出,而看到其中包含大量“Å”字符的奇怪文本,则可能是 UTF-8 被错误地解释为 ASCII。这是因为在 UTF-8 中表示大于一个字节的 Unicode 代码点的特殊序列通常以一个字节开头,该字节的数值与ASCII中的字母“Å”的数值相同(好吧,ISO/IEC 8859,但是足够近)。
类似地,如果你得到日语并且没有预料到它,根据我的经验,这通常是因为你给了计算机一些字节并告诉它它们是 UTF-16 编码的字符串,而实际上它们是 UTF-8。随着您的工作越来越多,您在识别这些模式方面会变得更有经验,它可以帮助您更快地修复错误。
就在上周,那里的最后一个示例为我节省了相当多的时间:我立即知道我的源数据一定是 UTF-8,因此能够迅速决定将字节副本删除到std::wstring我一直在尝试的. 以与编码无关的方式检查字节也揭示了“Å”模式,然后就是这样。这很重要,因为我没有数据源的文档,因此无法只查找编码应该是什么。我不得不猜测/推断它。希望您不会遇到这种情况。
| 归档时间: |
|
| 查看次数: |
3681 次 |
| 最近记录: |