C++ Unicode вопросы

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

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

В частности:

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

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

РЕДАКТИРОВАТЬ: Кроме того, глядя на стандарт C++0x и заметил литералы для utf8, utf16 и utf32, означает ли это, что стандартная библиотека (например, строки, потоки и т. Д.) Будет полностью поддерживать эти кодировки и преобразование между ними? Если так, то кто-нибудь понял, как скоро Visual Studio будет поддерживать эти функции?

РЕДАКТИРОВАТЬ 2: Что касается использования существующей поддержки C++, я буду искать локаль и аспекты.

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

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

привел к следующему hex в файле
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 ответов

Что я действительно хочу, так это что-то вроде 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/

Вот как я использую 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"));

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

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

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

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

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

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

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

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

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

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