【问题标题】:C++ convert ASII escaped unicode string into utf8 stringC++ 将 ASII 转义的 unicode 字符串转换为 utf8 字符串
【发布时间】:2015-02-16 03:41:53
【问题描述】:

我需要读取带有 unicode 转义的标准 ascii 样式字符串,并将其转换为包含 utf8 编码等效项的 std::string。因此,例如“\u03a0”(具有 6 个字符的 std::string)应转换为具有两个字符的 std::string,分别为原始二进制文件 0xce 和 0xa0。

如果有使用 icu 或 boost 的简单答案,我会非常高兴,但我一直找不到。

(这类似于Convert a Unicode string to an escaped ASCII string,但请注意,我最终需要达到 UTF8 编码。如果我们可以使用 Unicode 作为中间步骤就可以了。)

【问题讨论】:

  • “\u03a0”(假设 \ 是您输入中的实际反斜杠)5 个字符如何?
  • 因为我数不清,谢谢(已编辑)

标签: c++ unicode utf-8


【解决方案1】:

试试这样的:

std::string to_utf8(uint32_t cp)
{
    /*
    if using C++11 or later, you can do this:

    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
    return conv.to_bytes( (char32_t)cp );

    Otherwise...
    */

    std::string result;

    int count;
    if (cp <= 0x007F)
        count = 1
    else if (cp <= 0x07FF)
        count = 2;
    else if (cp <= 0xFFFF)
        count = 3;
    else if (cp <= 0x10FFFF)
        count = 4;
    else
        return result; // or throw an exception

    result.resize(count);

    if (count > 1)
    {
        for (int i = count-1; i > 0; --i)
        {
            result[i] = (char) (0x80 | (cp & 0x3F));
            cp >>= 6;
        }

        for (int i = 0; i < count; ++i)
            cp |= (1 << (7-i));
    }

    result[0] = (char) cp;

    return result;
}

std::string str = ...; // "\\u03a0"
std::string::size_type startIdx = 0;
do
{
    startIdx = str.find("\\u", startIdx);
    if (startIdx == std::string::npos) break;

    std::string::size_type endIdx = str.find_first_not_of("0123456789abcdefABCDEF", startIdx+2);
    if (endIdx == std::string::npos) break;

    std::string tmpStr = str.substr(startIdx+2, endIdx-(startIdx+2));
    std::istringstream iss(tmpStr);

    uint32_t cp;
    if (iss >> std::hex >> cp)
    {
        std::string utf8 = to_utf8(cp);
        str.replace(startIdx, 2+tmpStr.length(), utf8);
        startIdx += utf8.length();
    }
    else
        startIdx += 2;
}
while (true);

【讨论】:

  • std::string to_utf8() 中有几个错别字,但在改正之后,效果很好。
  • @GeorgeHernando 我做了一些调整
【解决方案2】:

(\u03a0 是 UTF-8 编码为 0xCE 0xA0 的希腊大写字母 PI 的 Unicode 代码点)

你需要:

  1. 从字符串“\u03a0”中获取数字 0x03a0:去掉反斜杠和 u 并将 03a0 解析为十六进制,转换为 wchar_t。重复直到你得到一个(宽)字符串。
  2. 将 0x3a0 转换为 UTF-8。 C++11 有一个 codecvt_utf8 可能会有所帮助。

【讨论】:

    【解决方案3】:

    我的解决方案:

    convert_unicode_escape_sequences(str)
    
    input: "\u043f\u0440\u0438\u0432\u0435\u0442"
    output: "привет"
    

    用于 wchar/chars 转换的 Boost:

    #include <boost/locale/encoding_utf.hpp>
    
    using boost::locale::conv::utf_to_utf;
    
    inline uint8_t get_uint8(uint8_t h, uint8_t l)
    {
        uint8_t ret;
    
        if (h - '0' < 10)
            ret = h - '0';
        else if (h - 'A' < 6)
            ret = h - 'A' + 0x0A;
        else if (h - 'a' < 6)
            ret = h - 'a' + 0x0A;
    
        ret = ret << 4;
    
        if (l - '0' < 10)
            ret |= l - '0';
        else if (l - 'A' < 6)
            ret |= l - 'A' + 0x0A;
        else if (l - 'a' < 6)
            ret |= l - 'a' + 0x0A;
        return  ret;
    }
    
    std::string wstring_to_utf8(const std::wstring& str)
    {
        return utf_to_utf<char>(str.c_str(), str.c_str() + str.size());
    }
    
    std::string convert_unicode_escape_sequences(const std::string& source)
    {
        std::wstring ws; ws.reserve(source.size());
        std::wstringstream wis(ws);
    
        auto s = source.begin();
        while (s != source.end())
        {
            if (*s == '\\')
            {
                if (std::distance(s, source.end()) > 5)
                {
                    if (*(s + 1) == 'u')
                    {
                        unsigned int v = get_uint8(*(s + 2), *(s + 3)) << 8;
                        v |= get_uint8(*(s + 4), *(s + 5));
    
                        s += 6;
                        wis << boost::numeric_cast<wchar_t>(v);
                        continue;
                    }
                }
            }
            wis << wchar_t(*s);
            s++;
        }
    
        return wstring_to_utf8(wis.str());
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-09
      • 2014-01-29
      • 1970-01-01
      相关资源
      最近更新 更多