Как преобразовать строку типа "\ u94b1" в один реальный символ в С++?

Мы знаем в строковом литерале, "\ u94b1" будет преобразован в символ, в данном случае - китайское слово "钱". Но если это буква буквально 6 символов в строке, говоря "\", "u", "9", "4", "b", "1", как я могу преобразовать ее в символ вручную?

Например:

string s1;
string s2 = "\u94b1";
cin >> s1;            //here I input \u94b1
cout << s1 << endl;   //here output \u94b1
cout << s2 << endl;   //and here output 钱

Я хочу преобразовать s1, чтобы cout << s1 << endl; также выводил .

Любое предложение пожалуйста?

Ответ 1

Фактически преобразование немного сложнее.

string s2 = "\u94b1";

на самом деле эквивалентно:

char cs2 = { 0xe9, 0x92, 0xb1, 0}; string s2 = cs2;

Это означает, что вы инициализируете его тремя символами, которые составляют представление UTF8 钱 - you char, просто проверьте s2.c_str(), чтобы убедиться в этом.


Итак, чтобы обработать 6 необработанных символов '\', 'u', '9', '4', 'b', '1', вы должны сначала извлечь wchar_t из string s1 = "\\u94b1"; (что вы получаете, когда вы прочитайте его). Это легко, просто пропустите два первых символа и прочитайте их как шестнадцатеричные:

unsigned int ui;
std::istringstream is(s1.c_str() + 2);
is >> hex >> ui;

ui теперь 0x94b1.

Теперь, если у вас есть совместимая с С++ 11 система, вы можете преобразовать ее с помощью std::convert_utf8:

wchar_t wc = ui;
std::codecvt_utf8<wchar_t> conv;
const wchar_t *wnext;
char *next;
char cbuf[4] = {0}; // initialize the buffer to 0 to have a terminating null
std::mbstate_t state;
conv.out(state, &wc, &wc + 1, wnext, cbuf, cbuf+4, next);

cbuf содержит теперь 3 символа, представляющих 钱 в utf8 и завершающий нуль, и вы можете окончательно выполнить:

string s3 = cbuf;
cout << s3 << endl;

Ответ 2

Вы делаете это, записывая код, который проверяет, содержит ли строка обратную косую черту, букву u и четыре шестнадцатеричные цифры и преобразует ее в кодовую точку Юникода. Тогда ваша реализация std::string, вероятно, предполагает UTF-8, поэтому вы переводите эту кодовую точку в 1, 2 или 3 байта UTF-8.

За дополнительными точками выясните, как вводить кодовые точки вне базовой плоскости.

Ответ 3

С utfcpp (только заголовок):

#include </usr/include/utf8.h>

#include <cstdint>
#include <iostream>

std::string replace_utf8_escape_sequences(const std::string& str) {
    std::string result;
    std::string::size_type first = 0;
    std::string::size_type last = 0;
    while(true) {
        // Find an escape position
        last = str.find("\\u", last);
        if(last == std::string::npos) {
            result.append(str.begin() + first, str.end());
            break;
        }

        // Extract a 4 digit hexadecimal
        const char* hex = str.data() + last + 2;
        char* hex_end;
        std::uint_fast32_t code = std::strtoul(hex, &hex_end, 16);
        std::string::size_type hex_size = hex_end - hex;

        // Append the leading and converted string
        if(hex_size != 4) last = last + 2 + hex_size;
        else {
            result.append(str.begin() + first, str.begin() + last);
            try {
                utf8::utf16to8(&code, &code + 1, std::back_inserter(result));
            }
            catch(const utf8::exception&) {
                // Error Handling
                result.clear();
                break;
            }
            first = last = last + 2 + 4;
        }
    }
    return result;
}

int main()
{
    std::string source = "What is the meaning of '\\u94b1'  '\\u94b1' '\\u94b1' '\\u94b1' ?";
    std::string target = replace_utf8_escape_sequences(source);
    std::cout << "Conversion from \"" << source << "\" to \"" << target << "\"\n";
}