Как преобразовать UTF-8 std::string в UTF-16 std::wstring?

Если у меня есть UTF-8 std::string как мне конвертировать его в UTF-16 std::wstring? На самом деле, я хочу сравнить два персидских слова.

4 ответа

Решение

Вот код Только слегка проверено и, возможно, есть несколько улучшений. Вызовите эту функцию, чтобы преобразовать строку UTF-8 в строку UTF-16. Если он думает, что входная строка не UTF-8, то он выдаст исключение, в противном случае он возвращает эквивалентную строку UTF-16.

std::wstring utf8_to_utf16(const std::string& utf8)
{
    std::vector<unsigned long> unicode;
    size_t i = 0;
    while (i < utf8.size())
    {
        unsigned long uni;
        size_t todo;
        bool error = false;
        unsigned char ch = utf8[i++];
        if (ch <= 0x7F)
        {
            uni = ch;
            todo = 0;
        }
        else if (ch <= 0xBF)
        {
            throw std::logic_error("not a UTF-8 string");
        }
        else if (ch <= 0xDF)
        {
            uni = ch&0x1F;
            todo = 1;
        }
        else if (ch <= 0xEF)
        {
            uni = ch&0x0F;
            todo = 2;
        }
        else if (ch <= 0xF7)
        {
            uni = ch&0x07;
            todo = 3;
        }
        else
        {
            throw std::logic_error("not a UTF-8 string");
        }
        for (size_t j = 0; j < todo; ++j)
        {
            if (i == utf8.size())
                throw std::logic_error("not a UTF-8 string");
            unsigned char ch = utf8[i++];
            if (ch < 0x80 || ch > 0xBF)
                throw std::logic_error("not a UTF-8 string");
            uni <<= 6;
            uni += ch & 0x3F;
        }
        if (uni >= 0xD800 && uni <= 0xDFFF)
            throw std::logic_error("not a UTF-8 string");
        if (uni > 0x10FFFF)
            throw std::logic_error("not a UTF-8 string");
        unicode.push_back(uni);
    }
    std::wstring utf16;
    for (size_t i = 0; i < unicode.size(); ++i)
    {
        unsigned long uni = unicode[i];
        if (uni <= 0xFFFF)
        {
            utf16 += (wchar_t)uni;
        }
        else
        {
            uni -= 0x10000;
            utf16 += (wchar_t)((uni >> 10) + 0xD800);
            utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00);
        }
    }
    return utf16;
}

Вот как вы делаете это с C++ 11:

std::string str = "your string in utf8";
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>> converter;
std::wstring wstr = converter.from_bytes(str);

И это те заголовки, которые вам нужны:

#include <iostream>
#include <string>
#include <locale>
#include <codecvt>

Более полный пример доступен здесь: http://en.cppreference.com/w/cpp/locale/wstring_convert/from_bytes

Здесь и здесь есть некоторые важные вопросы и ответы, которые стоит прочитать.

По сути, вам нужно преобразовать строку в общий формат - я всегда предпочитаю конвертировать в UTF-8, но ваш пробег может быть опасным.

Для конвертации было написано много программного обеспечения - конверсия довольно проста и может быть написана за несколько часов - однако почему бы не взять что-то уже сделанное, такое как UTF-8 CPP

Эта страница также кажется полезной: http://www.codeproject.com/KB/string/UtfConverter.aspx

В разделе комментариев этой страницы есть также некоторые интересные предложения для этой задачи, такие как:

// Get en ASCII std::string from anywhere
std::string sLogLevelA = "Hello ASCII-world!";

std::wstringstream ws;
ws << sLogLevelA.c_str();
std::wstring sLogLevel = ws.str();

Или же

// To std::string:
str.assign(ws.begin(), ws.end());
// To std::wstring
ws.assign(str.begin(), str.end());

Хотя я не уверен в правильности этих подходов...

Для преобразования между двумя типами вы должны использовать: std:: codecvt_utf8_utf16
Обратите внимание на строковые префиксы, которые я использую для определения UTF16 (L) и UTF8 (u8).

#include <string>

#include <codecvt>

int main()
{

    std::string original8 = u8"הלו";

    std::wstring original16 = L"הלו";

    //C++11 format converter
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;

    //convert to UTF8 and std::string
    std::string utf8NativeString = convert.to_bytes(original16);

    std::wstring utf16NativeString = convert.from_bytes(original8);

    assert(utf8NativeString == original8);
    assert(utf16NativeString == original16);

    return 0;
}

Microsoft разработала прекрасную библиотеку для таких преобразований в рамках своего проекта Casablanca, также называемого CPPRESTSDK. Это отмечено под пространством имен служебной программой:: преобразования.

Простое его использование будет выглядеть примерно так при использовании пространства имен

Утилита:: преобразования

utf8_to_utf16("sample_string");
Другие вопросы по тегам