Невозможно извлечь символы Unicode из C ++ std :: string - PullRequest
1 голос
/ 06 февраля 2020

Я хочу прочитать C ++ std :: string, затем передать эту std :: string функции, которая будет анализировать ее, затем извлечь из нее символы Unicode и простые символы ASCII.

Я искал много учебники онлайн, но все они упоминали, что стандартный C ++ не полностью поддерживает формат Unicode. Многие из них упоминали, что используют ICU C ++ .

. Это моя программа на C ++, предназначенная для понимания основ c вышеуказанных функций. Он считывает необработанную строку, преобразует ее в строку Unicode ICU и печатает, что:

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

int main()
{
    std::string s="Hello☺";
    // at this point s contains a line of text
    // which may be ANSI or UTF-8 encoded

    // convert std::string to ICU's UnicodeString
    icu::UnicodeString ucs = icu::UnicodeString::fromUTF8(icu::StringPiece(s.c_str()));

    // convert UnicodeString to std::wstring
    std::wstring ws;
    for (int i = 0; i < ucs.length(); ++i)
      ws += static_cast<wchar_t>(ucs[i]);

    std::wcout << ws << std::endl;
}

Ожидаемый результат:

Hello☺

Фактический результат:

Hello?

Пожалуйста, предложите Что я делаю неправильно. Также предложите любые альтернативные / более простые подходы

Спасибо

Обновление 1 (более старая версия): Рабочий код выглядит следующим образом:

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

void f(const std::string & s)
{
  std::wcout << "Inside called function" << std::endl;
  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());

  // at this point s contains a line of text which may be ANSI or UTF-8 encoded

  // convert std::string to ICU's UnicodeString
  icu::UnicodeString ucs = icu::UnicodeString::fromUTF8(icu::StringPiece(s.c_str()));

  // convert UnicodeString to std::wstring
  std::wstring ws;
  for (int i = 0; i < ucs.length(); ++i)
    ws += static_cast<wchar_t>(ucs[i]);

  std::wcout << ws << std::endl;
}

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::wcout << "Inside main function" << std::endl;

    std::string s=u8"hello☺";
    // at this point s contains a line of text which may be ANSI or UTF-8 encoded

    // convert std::string to ICU's UnicodeString
    icu::UnicodeString ucs = icu::UnicodeString::fromUTF8(icu::StringPiece(s.c_str()));

    // convert UnicodeString to std::wstring
    std::wstring ws;
    for (int i = 0; i < ucs.length(); ++i)
      ws += static_cast<wchar_t>(ucs[i]);

    std::wcout << ws << std::endl;
    std::wcout << "--------------------------------" << std::endl;
    f(s);
    return 0;
}

Теперь, ожидаемый и фактический выходные данные одинаковы, то есть:

Inside main function
hello☺
--------------------------------
Inside called function
hello☺

Обновление 2 (последнее): Код, упомянутый в обновлении 1, не работает для символов UTF32, таких как ?. Итак, рабочий код для всех возможных символов Unicode выглядит следующим образом. Отдельное спасибо @ Botje за его решение. Я sh Я могу поставить более одного тика в его решение !!! :)

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

void f(const std::u32string & s)
{
  std::wcout << "INSIDE CALLED FUNCTION:" << std::endl;

  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;

  std::cout << "--------------------------------" << std::endl;
}

int main()
{
    std::cout << "--------------------------------" << std::endl;
    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::wcout << "INSIDE MAIN FUNCTION:" << std::endl;

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

    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;

    std::cout << "--------------------------------" << std::endl;
    f(s);
    return 0;
}

Теперь ожидаемый и фактический выходные данные совпадают, то есть:

--------------------------------
INSIDE MAIN FUNCTION:
Unicode string is: hello☺?
Size of unicode string = 7
Individual characters of the string are:
h
e
l
l
o
☺
?
--------------------------------
INSIDE CALLED FUNCTION:
Unicode string is: hello☺?
Size of unicode string = 7
Individual characters of the string are:
h
e
l
l
o
☺
?
--------------------------------

1 Ответ

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

Есть несколько камней преткновения, чтобы получить это право:

  • Во-первых, ваш файл (и смайлик на нем) должен быть закодирован как UTF-8. Смайлик должен состоять из буквальных байтов 0xE2 0x98 0xBA.
  • . Вы должны пометить строку как содержащую данные UTF-8, используя декоратор u8: u8"Hello☺"
  • Далее документация из icu::UnicodeString отмечает, что он хранит Unicode как UTF-16. В этом случае вам повезло, поскольку U + 263A помещается в один символ UTF-16. Другие смайлики не могут! Вам следует либо преобразовать его в UTF-32, либо быть очень осторожным и использовать функцию GetChar32At.
  • Наконец, кодировка, используемая wcout, должна быть настроена на imbue в соответствии с кодировкой, ожидаемой ваше окружение. См. Ответы на этот вопрос .
...