c++ - 如何将utf8转换为std::string?

标签 c++ unicode utf-16 cjk cpprest-sdk

我正在处理此代码,该代码接收到包含base64_encoded有效负载(是json)的cpprest sdk响应。这是我的代码段:

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;

    }

我也尝试过,我发现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:(
}

我的问题是:可以将包含日语字符的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

}

感谢您的回答,当提到字符串只是存储时,它们会有所帮助。

最佳答案

您在这里混淆了不同的概念。

存储

这就是我们保存/存储/保存数据的方式。 std::stringchar的集合,它是字节。 std::wstringwchar_t的集合,它们有时是2字节宽的值(但这不能保证!)。

编码

这就是数据的含义以及应如何解释。 std::string是字节的集合,可以容纳UTF-8或UTF-16或UTF-32或ASCII或ShiftJIS或莫尔斯电码或JPEG或电影或我的DNA(幸运的字符串!)。 。

世界上有一些强有力的惯例。例如,在Windows上,通常接受std::wstring来保存UTF-16(因为两字节存储对此很方便,并且因为Windows API就是这样做的)。

较新的C++版本也为我们提供了诸如std::u16_stringstd::u32_string之类的东西,它们仍然没有直接的编码概念,而是打算分别用于UTF-16和UTF-32,因为它们的名称使读者更加明白这一意图。代码。 C++ 20将引入std::u8_string,它旨在表示UTF-8编码的字符串(否则或多或少类似于std::string)。

但这只是约定。关于std::string类型的任何内容都不会显示“UTF-8”或其他任何内容。它不了解,不关心或不执行任何编码。它只是存储字节。

因此,关于“将UTF-8转换为std::string”的问题实际上没有任何意义;就像问如何将道路转换成汽车一样。

“那我该怎么办?”

好吧,Base64也不是编码。好吧,实际上,它完全是,但是它是在字符串编码之上的一种编码。这是一种传输/转义/清除原始字节的方法,而不是描述以后如何解释它们的方法。通过asking cpprest to convert from Base64,这只是在改变原始字节的提供方式。这就是为什么它为您提供std::vector<char>而不是std::string的原因,因为尽管(如上所述)std::string并不关心编码,但我们有时还是会使用std::vector<char>完全正确地说“此集合没有任何特定的编码,因此,请不要试图从惯例或这种用例中的编码来猜测;它所知道的只是它是一堆字节。”这取决于意见。有些人仍然会使用std::string; cpprest的作者决定不这样做。

关键是,函数from_base64的使用无法告诉我们有关您检索到的文本编码的任何信息。为此,我们必须返回文本文档。我们无权访问,您也没有告诉我们任何信息。如果这只是一个JSON字符串,则编码将取决于cpprest JSON库,因此您已经完成了。但是,事实并非如此:创建JSON对象的人都会将其打包到Base64表示中。同样,这些信息不是您与我们共享的。

但是,根据您选择的变量名称,您正在查看的数据已经是UTF-8。然后,您尝试将其转换为UTF-16,这与您要描述的描述相反。

(类似地,在第二个示例中,您使用了a std::wstring that [probably] already stores UTF-16 thanks to the L"wide string literal" ,然后告诉计算机它是UTF-8,并将其“再次”转换为UTF-16,然后将原始字节提取为std::string。这都没有道理。 )

相反,为什么不从字面上看只是processXML(utf8_payload);呢?

一般建议

编码可能非常复杂,尽管一旦您将所有这些抽象层的基本概念都放在脑海中,处理起来就容易得多。对于 future ,以及对于这个问题,如果您想澄清一下,您将需要确保在数据“流水线”的每个阶段从位置A传输到位置B并获得数据时绝对清楚从类型C转换为类型D,以及其他方式,说明在每个步骤中应使用哪种编码。如果您想在其中一个步骤中更改编码,则可以这样做(尽管这种情况很少见!)。但是在编写任何代码之前,请确保您确定自己需要什么,否则您将陷入困境。

最终,您将开始发现有帮助的模式。例如,如果您期望获得一些美味的非ASCII输出,而看到的奇怪文本中包含很多“Å”字符,则可能是UTF-8被错误地解释为ASCII。这是因为这样的方式,即表示UTF-8中大于一个字节的Unicode代码点的特殊序列通常以其数值与ASCII中的字母“Å”相同的字节开头(嗯,ISO / IEC 8859,但是足够近)。

同样,如果您不懂日语,就我的经验而言,通常是因为您给了计算机一些字节,并告诉它它们是UTF-16编码的字符串,而实际上却是UTF-8。您在工作时会更加熟悉这些模式,因此可以帮助您更快地修复错误。

就在上周,那里的最后一个示例为我节省了很多时间:我立即知道我的源数据必须是UTF-8,因此能够快速决定将字节副本删除为我曾经使用过的std::wstring尝试。以与编码无关的方式检查字节也显示出“Å”模式,然后就是那样。这一点很重要,因为我没有数据源的文档,因此也没有办法仅查找编码的含义。我不得不猜测/推断。希望这里不是您的情况。

关于c++ - 如何将utf8转换为std::string?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55093790/

相关文章:

c++ - 使用 regex.h 时内存泄漏?

c++ - 用DLL注入(inject)C++读写

java - 在 Java 中将字符串转换为 UTF-16 表示形式

Java - 无法读取 ØÖ(特殊字符)并打印它

c++ - STL 重新分配 C++

c++ - 这是动态分配float变量的正确方法吗?

Java 无法打开文件名中包含替代 Unicode 值的文件?

regex - 正则表达式 仅限阿拉伯字符和数字

javascript - JS 编码解码 UTF 的问题?

c# - 删除字符串中除 "ñ"以外的重音符号