C++字符串代码点和代码单元的好解决方案?

C++字符串代码点和代码单元的好解决方案?,c++,unicode,utf-8,utf-16,C++,Unicode,Utf 8,Utf 16,在Java中,字符串具有以下方法: length()/charAt(), codePointCount()/codePointAt() C++11的std::string a=u8很烫烫的一锅汤; 但是a.size是字符数组的长度,不能索引unicode字符 在C++字符串中有Unicode的解决方案吗?< /P> < P>我通常在做字符操作之前将UTF-8字符串转换成一个宽的UTF-32/UCS-2字符串。C++确实给了我们这样做的功能,但是它们不是非常友好的,所以我在这里写了一些更好的转换

在Java中,字符串具有以下方法:

length()/charAt(), codePointCount()/codePointAt()
C++11的std::string a=u8很烫烫的一锅汤;

但是a.size是字符数组的长度,不能索引unicode字符

在C++字符串中有Unicode的解决方案吗?< /P> < P>我通常在做字符操作之前将UTF-8字符串转换成一个宽的UTF-32/UCS-2字符串。C++确实给了我们这样做的功能,但是它们不是非常友好的,所以我在这里写了一些更好的转换函数:

// This should convert to whatever the system wide character encoding 
// is for the platform (UTF-32/Linux - UCS-2/Windows)
std::string ws_to_utf8(std::wstring const& s)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> cnv;
    std::string utf8 = cnv.to_bytes(s);
    if(cnv.converted() < s.size())
        throw std::runtime_error("incomplete conversion");
    return utf8;
}

std::wstring utf8_to_ws(std::string const& utf8)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> cnv;
    std::wstring s = cnv.from_bytes(utf8);
    if(cnv.converted() < utf8.size())
        throw std::runtime_error("incomplete conversion");
    return s;
}

int main()
{
    std::string s = u8"很烫烫的一锅汤";

    auto w = utf8_to_ws(s); // convert to wide (UTF-32/UCS-2)

    // now we can use code-point indexes on the wide string

    std::cout << s << " is " << w.size() << " characters long" << '\n';
}
如果您希望在不考虑平台的情况下与UTF-32进行转换,则可以使用以下未经良好测试的转换例程:

std::string utf32_to_utf8(std::u32string const& utf32)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cnv;
    std::string utf8 = cnv.to_bytes(utf32);
    if(cnv.converted() < utf32.size())
        throw std::runtime_error("incomplete conversion");
    return utf8;
}

std::u32string utf8_to_utf32(std::string const& utf8)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cnv;
    std::u32string utf32 = cnv.from_bytes(utf8);
    if(cnv.converted() < utf8.size())
        throw std::runtime_error("incomplete conversion");
    return utf32;
}
注意:从C++17开始,std::wstring_convert已被弃用


但是我还是喜欢使用它而不是第三方库,因为它是可移植的,避免了外部依赖,在提供替换之前,它不会被删除。在所有情况下,替换这些函数的实现都很容易,而不必更改使用它们的所有代码。

您检查过这个答案吗?:我通常将utf-8转换为utf-32/UCS-2 std::wstring,以便每个代码点都是一个字符。这里的答案中有代码需要转换:否则使用库UCS-2没有空间容纳所有汉字。@RickJames:Galik的意思可能是UTF-16,而不是UTF-16没有空间容纳单个“字符”中的所有汉字。所以a.size我认为是不正确的。很酷,但我看到一些讨论,其中说,在不同的平台上,wchar\u t可以是uint16\u t,而不是uint32\u t。在为unicode字符串中的字符编制索引时可能会出错。@您应该知道,对于每个平台,这应该正确转换。在Windows上,它将创建以UCS-2编码的2字节wchar\u t字符,在Linux上,它将创建以UTF-32编码的4字节wchar\u t字符。这将很好地工作,直到有人去给你一个带有“@MilesBudnek”的字符串,我添加了代码,以转换为UTF-32,而不管我假设的平台是什么,如果要解决任何问题,2字符编码可能会使您的字符在Linux上工作正常我无法在Windows上测试不幸的是,当前所有现有的Unicode代码点都将适合单个UTF-32单元。
std::string utf32_to_utf8(std::u32string const& utf32)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cnv;
    std::string utf8 = cnv.to_bytes(utf32);
    if(cnv.converted() < utf32.size())
        throw std::runtime_error("incomplete conversion");
    return utf8;
}

std::u32string utf8_to_utf32(std::string const& utf8)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> cnv;
    std::u32string utf32 = cnv.from_bytes(utf8);
    if(cnv.converted() < utf8.size())
        throw std::runtime_error("incomplete conversion");
    return utf32;
}