Как мне ввести 4-байтовые символы UTF-8?

Я пишу небольшое приложение, которое мне нужно протестировать с символами utf-8 разного количества байтов.

Я могу ввести символы юникода для тестирования, которые хорошо закодированы в utf-8 с 1,2 и 3 байтами, выполнив, например:

string in = "pi = \u3a0";

Но как мне получить символ Unicode, который закодирован с 4 байтами? Я пытался:

string in = "aegan check mark = \u10102";

Который, насколько я понимаю, должен выводить. Но когда я распечатываю это, я получаю ᴶ0

Что мне не хватает?

РЕДАКТИРОВАТЬ:

Я получил его на работу, добавив ведущие нули:

string in = "\U00010102";

Жаль, что я думал об этом раньше:)

1 ответ

Решение

В паттерне есть более длинная форма побега \U с последующими восемью цифрами, а не \u следуют четыре цифры. Это также используется в Java и Python, среди прочего:

>>> '\xf0\x90\x84\x82'.decode("UTF-8")
u'\U00010102'

Однако, если вы используете строки байтов, почему бы просто не экранировать каждый байт, как описано выше, вместо того, чтобы полагаться на компилятор для преобразования escape в строку UTF-8? Это также может показаться более переносимым - если я скомпилирую следующую программу:

#include <iostream>
#include <string>

int main()
{
    std::cout << "narrow: " << std::string("\uFF0E").length() <<
        " utf8: " << std::string("\xEF\xBC\x8E").length() <<
        " wide: " << std::wstring(L"\uFF0E").length() << std::endl;

    std::cout << "narrow: " << std::string("\U00010102").length() <<
        " utf8: " << std::string("\xF0\x90\x84\x82").length() <<
        " wide: " << std::wstring(L"\U00010102").length() << std::endl;
}

На win32 с моими текущими настройками cl выдает:

warning C4566: character represented by universal-character-name '\UD800DD02' cannot be represented in the current code page (932)

Компилятор пытается преобразовать все экранированные символы Юникода в байтовых строках в системную кодовую страницу, которая в отличие от UTF-8 не может представлять все символы Юникода. Как ни странно, он понял, что \U00010102 является \uD800\uDD02 в UTF-16 (его внутреннее представление в юникоде) и искалечил escape в сообщении об ошибке...

При запуске программа печатает:

narrow: 2 utf8: 3 wide: 1
narrow: 2 utf8: 4 wide: 2

Обратите внимание, что байтовые строки UTF-8 и широкие строки верны, но компилятору не удалось преобразовать "\U00010102", давая байтовую строку "??"неверный результат.

Другие вопросы по тегам