Как преобразовать std :: string в std :: u32string в C ++ 11? - PullRequest
0 голосов
/ 08 февраля 2020

Я работаю с Unicode в C ++ 11 и сейчас я не могу преобразовать std :: string в std :: u32string.

Мой код выглядит следующим образом:

#include <iostream>
#include <string>
#include <locale>
#include "unicode/unistr.h"
#include "unicode/ustream.h"

int main()
{
    constexpr char locale_name[] = "";
    setlocale( LC_ALL, locale_name );
    std::locale::global(std::locale(locale_name));
    std::ios_base::sync_with_stdio(false);
    std::wcin.imbue(std::locale());
    std::wcout.imbue(std::locale());

    std::string str="hello☺?";

    std::u32string s(str.begin(),str.end());

    icu::UnicodeString ustr = icu::UnicodeString::fromUTF32(reinterpret_cast<const UChar32 *>(s.c_str()), s.size());
    std::cout << "Unicode string is: " << ustr << std::endl;

    std::cout << "Size of unicode string = " << ustr.countChar32() << std::endl;

    std::cout << "Individual characters of the string are:" << std::endl;
    for(int i=0; i < ustr.countChar32(); i++)
      std::cout << icu::UnicodeString(ustr.char32At(i)) << std::endl;

    return 0;
}

При выполнении вывод: (что не ожидается)

Unicode string is: hello�������
Size of unicode string = 12
Individual characters of the string are:
h
e
l
l
o
�
�
�
�
�
�
�

Пожалуйста, предложите, если какая-либо функция библиотеки ICU существует для этого

Ответы [ 2 ]

2 голосов
/ 08 февраля 2020

Вывод имеет смысл. Предположительно, вы думали, что определяете строку из 7 символов? Посмотрите на str.size(). Вы определили строку из 12 символов!

Несмотря на то, что вы смогли набрать "hello☺?" в своей программе, этот строковый литерал не состоит всего из семи байтов. Каждый из последних двух символов расширяется в несколько байтов, поскольку эти символы выходят за пределы расширенного диапазона ASCII (от 0 до 255 или от -128 до 127). Результатом является 12-байтовый строковый литерал, который инициализирует 12-символьный string, что, в свою очередь, инициализирует 12-символьный u32string. Вы искали символы, которые вы хотели представить.

Пример: Символ '☺' представлен в виде трех байтов \0xE2\0x98\0xBA. Если char подписано в вашей системе (вероятно), эти три байта принимают значения -30, -104 и -70. Преобразование в char32_t переводит каждое из этих значений в 32 бита, а затем преобразует подписанное в беззнаковое, в результате чего получаются три значения 4294967266, 4294967192 и 4294967226. Предположительно, вы хотели объединить эти байты в одно char32_t значение \0x00E298BA. Однако ваше преобразование не обеспечивает механизм (пере) объединения байтов.

Аналогично, символ '?' представлен четырьмя байтами \0xF0\0x9F\0x98\0x86. Они были преобразованы в четыре 32-разрядных целых числа вместо единственного значения \0xF09F9886.

Чтобы получить желаемый результат, необходимо указать компилятору интерпретировать строковый литерал как 7 символов. Попробуйте следующую инициализацию s:

std::u32string s = U"hello☺?";

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


Бесплатный прием отладки: Когда ваш вывод это не то, что вы ожидаете, проверьте данные на каждом этапе, чтобы убедиться, что ваш вход соответствует вашим ожиданиям.

0 голосов
/ 09 февраля 2020

Спасибо всем за помощь!

Используя эти 2 ссылки, я смог найти несколько соответствующих функций:

Я пытался использовать функции codecvt , но я получил ошибку:

fatal error: codecvt: No such file or directory
 #include <codecvt>
                   ^
compilation terminated.

Итак, я пропустил это и при дальнейшем поиске я нашел mbrtoc32() функцию, которая работает:)

Это рабочий код:

#include <iostream>
#include <string>
#include <locale>
#include "unicode/unistr.h"
#include "unicode/ustream.h"
#include <cassert>
#include <cwchar>
#include <uchar.h>

int main()
{
    constexpr char locale_name[] = "";
    setlocale( LC_ALL, locale_name );
    std::locale::global(std::locale(locale_name));
    std::ios_base::sync_with_stdio(false);
    std::wcin.imbue(std::locale());
    std::wcout.imbue(std::locale());

    std::string str;
    std::cin >> str;
    //For example, the input string is "hello☺?"

    std::mbstate_t state{}; // zero-initialized to initial state
    char32_t c32;
    const char *ptr = str.c_str(), *end = str.c_str() + str.size() + 1;

    icu::UnicodeString ustr;

    while(std::size_t rc = mbrtoc32(&c32, ptr, end - ptr, &state))
    {
      icu::UnicodeString temp((UChar32)c32);
      ustr+=temp;
      assert(rc != (std::size_t)-3); // no surrogates in UTF-32
      if(rc == (std::size_t)-1) break;
      if(rc == (std::size_t)-2) break;
      ptr+=rc;
    }

    std::cout << "Unicode string is: " << ustr << std::endl;
    std::cout << "Size of unicode string = " << ustr.countChar32() << std::endl;
    std::cout << "Individual characters of the string are:" << std::endl;
    for(int i=0; i < ustr.countChar32(); i++)
      std::cout << icu::UnicodeString(ustr.char32At(i)) << std::endl;

    return 0;
}

Выход на входе hello☺? соответствует ожидаемому:

Unicode string is: hello☺?
Size of unicode string = 7
Individual characters of the string are:
h
e
l
l
o
☺
?
...