C ++ Unicode вопросы - PullRequest
       31

C ++ Unicode вопросы

6 голосов
/ 07 мая 2009

Мне известны ICU и небольшие библиотеки, такие как utf8, одна в проекте кода (забудьте точное имя), однако ни одна из них не является именно тем, что я хочу.

Что я действительно хочу, так это что-то вроде ICU, но в более дружеской манере.

В частности:

  • Полностью ориентированный на объект
  • Реализации стандартных потоков c ++ или хотя бы что-то, выполняющее ту же роль.
  • Может форматировать время, даты и т. Д. В зависимости от локали (например, дд / мм / гг в Великобритании и мм / дд / гг в США).
  • Позволяет мне выбрать «внутреннюю» кодировку строк, поэтому я могу, например, заставить ее использовать UTF-16 в окнах, чтобы избежать большого количества преобразований при передаче строк в и из Windows API и DirectX
  • Простое преобразование строк между кодировками

Если такой библиотеки не существует, можно ли обернуть ICU, используя стандартные классы c ++, поэтому я могу, например, создать ustring, которая будет идентично std :: string и std :: wstring, а также реализовать версии потоков (оптимально с их полной совместимостью с существующими, то есть я мог бы передать его функции, ожидающей std :: ostream, и она выполнит преобразование между своим внутренним форматом и ascii (или utf-8) на лету) ? Предполагая, что это возможно, сколько работы это будет?

EDIT: Также, посмотрев на стандарт c ++ 0x и заметив литералы для utf8, utf16 и utf32, означает ли это, что стандартная библиотека (например, строки, потоки и т. Д.) Будет полностью поддерживать эти кодировки и преобразование между ними? Если да, то кто-нибудь знает, сколько времени пройдет, пока Visual Studio не будет поддерживать эти функции?

EDIT2: Что касается использования существующей поддержки c ++, я посмотрю материал локали и аспектов.

Одна из проблем, с которыми я столкнулся, заключается в том, что при использовании потоков, определенных вокруг wchar_t, который составляет 2 байта под окнами для файлового ввода-вывода, все же кажется, что он все еще использует ascii для файлов, которые они сами.

std::wofstream file(L"myfile.txt", std::ios::out);
file << L"Hello World!" << std::endl;

привело к следующему гексу в файле
48 65 6C 6C 6F 20 57 6F 72 6C 64 0D 0A
что явно ascii, а не ожидаемый вывод utf-16:
FF FE 48 00 65 00 6C 00 6C 00 6F 00 20 00 57 00 6F 00 72 00 6C 00 64 00 0D 00 0A 00

Ответы [ 6 ]

3 голосов
/ 07 мая 2009

Что я действительно хочу, так это что-то вроде ICU, но в более дружеской манере

К сожалению, такой вещи не существует. Их API не ТАК ужасен, так что вы можете привыкнуть к нему с некоторыми усилиями.

Может форматировать время, даты и т. Д. В зависимости от локали (например, дд / мм / гг в Великобритании и мм / дд / гг в США).

В классе std::locale есть полная поддержка, читайте о том, как его использовать. Вы также можете указать локаль для std::iostream, чтобы она правильно форматировала числа, даты.

Простое преобразование строк между кодировками

std::locale предоставляет фасеты для охвата 8-битного локального кодирования для широкого и обратно.

так что я могу, например, заставить его использовать UTF-16

ICU использует utf-16 для внутреннего использования, win32 wchar_t и wstring также используют utf-16, в других ОС большинство реализаций дают wchar_t как utf-32, а wstring использует utf-32.

Замечания: Поддержка std::locale не идеальна, но она уже дает много инструментов, которые полезны для манипуляций с charrecter.

См .: http://www.cplusplus.com/reference/std/locale/

2 голосов
/ 07 мая 2009

Вот как я использую ICU для преобразования между std :: string (в UTF-8) и std :: wstring

/** Converts a std::wstring into a std::string with UTF-8 encoding.
 */
template < typename StringT >
StringT utf8 ( std::wstring const & rc_string );

/** Converts a std::String with UTF-8 encoding into a std::wstring.
 */
template < typename StringT >
StringT utf8 ( std::string const & rc_string );

/** Nop specialization for std::string.
 */
template < >
inline std::string utf8 ( std::string const & rc_string )
{
  return rc_string;
}

/** Nop specialization for std::wstring.
 */
template < >
inline std::wstring utf8 ( std::wstring const & rc_string )
{
  return rc_string;
}

template < >
std::string utf8 ( std::wstring const & rc_string )
{
  std::string result;
  if(rc_string.empty())
    return result;

  std::vector<UChar> buffer;

  result.resize(rc_string.size() * 3); // UTF-8 uses max 3 bytes per char
  buffer.resize(rc_string.size() * 2); // UTF-16 uses max 2 bytes per char

  UErrorCode status = U_ZERO_ERROR;
  int32_t len = 0;

  u_strFromWCS(
    &buffer[0],
    buffer.size(),
    &len,
    &rc_string[0],
    rc_string.size(),
    &status
  );
  if(!U_SUCCESS(status))
  {
    throw XXXException("utf8: u_strFromWCS failed");
  }
  buffer.resize(len);

  u_strToUTF8(
    &result[0],
    result.size(),
    &len,
    &buffer[0],
    buffer.size(),
    &status
  );
  if(!U_SUCCESS(status))
  {
    throw XXXException("utf8: u_strToUTF8 failed");
  }
  result.resize(len);

  return result;
}/* end of utf8 ( ) */


template < >
std::wstring utf8 ( std::string const & rc_string )
{
  std::wstring result;
  if(rc_string.empty())
    return result;

  std::vector<UChar> buffer;

  result.resize(rc_string.size());
  buffer.resize(rc_string.size());

  UErrorCode status = U_ZERO_ERROR;
  int32_t len = 0;

  u_strFromUTF8(
    &buffer[0],
    buffer.size(),
    &len,
    &rc_string[0],
    rc_string.size(),
    &status
  );
  if(!U_SUCCESS(status))
  {
    throw XXXException("utf8: u_strFromUTF8 failed");
  }
  buffer.resize(len);

  u_strToWCS(
    &result[0],
    result.size(),
    &len,
    &buffer[0],
    buffer.size(),
    &status
  );
  if(!U_SUCCESS(status))
  {
    throw XXXException("utf8: u_strToWCS failed");
  }
  result.resize(len);

  return result;
}/* end of utf8 ( ) */

Использовать это так просто:

std::string s = utf8<std::string>(std::wstring(L"some string"));
std::wstring s = utf8<std::wstring>(std::string("some string"));
1 голос
/ 09 октября 2011

Я всегда работаю таким образом:

поток байтов в некоторой кодировке -> ICU -> wistream -> stl & boost -> wostream -> ICU -> поток байтов в некоторой кодировке

1 голос
/ 07 мая 2009

Форматирование даты, времени и т. Д. Может быть сделано путем указания конкретной локали. Что касается прокрутки собственного - это всегда возможно, беря столько или меньше из базовой библиотеки, сколько вам нужно.

Также, посмотрев на стандарт c ++ 0x и заметив литералы для utf8, utf16 и utf32, означает ли это, что стандартная библиотека (например, строки, потоки и т. Д.) Будет полностью поддерживать эти кодировки и преобразование между ними?

Да. Но обратите внимание, что это разные типы данных, а не обычная последовательность wchar или wstring.

Если так, то кто-нибудь знает, сколько времени пройдет до тех пор, пока Visual Studio не будет поддерживать эти функции?

Насколько мне известно: vc9 (VS2008) имеет лишь частичную поддержку некоторых функций TR1. Ожидается, что vc10 (VS2010) получит лучшую поддержку.

0 голосов
/ 07 мая 2009

Неудача. Я знаю, что библиотеки Dinkumware предлагают некоторую поддержку Unicode - вы можете посмотреть документацию на их веб-сайте. AFAIK, это не бесплатно.

0 голосов
/ 07 мая 2009

Я сделал свою собственную маленькую обертку. Я могу поделиться, если хотите.

...