Каков оптимальный мультиплатформенный способ работы с строками Unicode в С++?

Я знаю, что в StackOverflow уже есть несколько вопросов о std::string versus std::wstring или аналогичных, но ни одно из них не предложило полного решения.

Чтобы получить хороший ответ, я должен определить требования:

  • мультиплатформенный, должен работать на Windows, OS X и Linux.
  • минимальное усилие для преобразования в/из специфичных для платформы строк Unicode, таких как CFStringRef, wchar_t *, char* как UTF-8 или других типов, как того требует OS API. Примечание. Мне не нужна поддержка конвертации кода кода, потому что я ожидаю использовать только совместимые с Unicode функции во всех поддерживаемых операционных системах.
  • Если требуется внешняя библиотека, это должно быть с открытым исходным кодом и под очень либеральной лицензией, например BSD, но не с LGPL.
  • использовать синтаксис printf format.
  • простой способ выделения/освобождения строк
  • производительность не очень важна, поскольку я предполагаю, что строки Unicode используются только для пользовательского интерфейса приложения.
  • можно было бы оценить некоторый пример

Я бы по достоинству оценил только одно предлагаемое решение за каждый ответ, делая это, люди могут голосовать за свою предпочтительную альтернативу. Если у вас несколько альтернатив, просто добавьте еще один ответ.

Просьба указать что-то, что действительно сработало для вас.

Похожие вопросы:

Ответы

Ответ 1

То же, что и ответ Адама Розенфилда (+1), но вместо этого я использую UTFCPP.

Ответ 2

Я настоятельно рекомендую использовать UTF-8 внутри вашего приложения, используя обычные старые char* или std::string для хранения данных. Для взаимодействия с API, использующими другую кодировку (ASCII, UTF-16 и т.д.), Я бы рекомендовал использовать libiconv, что лицензирован под LGPL.

Пример использования:

class TempWstring
{
public:
  TempWstring(const char *str)
  {
    assert(sUTF8toUTF16 != (iconv_t)-1);
    size_t inBytesLeft = strlen(str);
    size_t outBytesLeft = 2 * (inBytesLeft + 1);  // worst case
    mStr = new char[outBytesLeft];
    char *outBuf = mStr;
    int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft);
    assert(result == 0 && inBytesLeft == 0);
  }

  ~TempWstring()
  {
    delete [] mStr;
  }

  const wchar_t *Str() const { return (wchar_t *)mStr; }

  static void Init()
  {
    sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8");
    assert(sUTF8toUTF16 != (iconv_t)-1);
  }

  static void Shutdown()
  {
    int err = iconv_close(sUTF8toUTF16);
    assert(err == 0);
  }

private:
  char *mStr;

  static iconv_t sUTF8toUTF16;
};

iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1;

// At program startup:
TempWstring::Init();

// At program termination:
TempWstring::Shutdown();

// Now, to convert a UTF-8 string to a UTF-16 string, just do this:
TempWstring x("Entr\xc3\xa9""e");  // "Entrée"
const wchar_t *ws = x.Str();  // valid until x goes out of scope

// A less contrived example:
HWND hwnd = CreateWindowW(L"class name",
                          TempWstring("UTF-8 window title").Str(),
                          dwStyle, x, y, width, height, parent, menu, hInstance, lpParam);

Ответ 3

Недавно я был в проекте, который решил использовать std:: wstring для кросс-платформенного проекта, потому что "широкие строки - это Unicode, правильно?" Это привело к ряду головных болей:

  • Насколько велика скалярная величина в wstring? Ответ: Это до реализации компилятора. В Visual Studio (Win) это 16 бит. Но в Xcode (Mac) это 32 бита.
  • Это привело к неудачному решению использовать UTF-16 для связи по кабелю. Но какой UTF-16? Есть два: UTF-16BE (big-endian) и UTF16-LE (little-endian). Неясно, что это привело к еще большему количеству ошибок.

Когда вы используете код, специфичный для платформы, имеет смысл использовать собственное представление платформы для связи с его API. Но для любого кода, который используется на разных платформах или обменивается между платформами, избегайте всей двусмысленности и используйте UTF-8.

Ответ 4

Правило большого пальца: используйте форму платформы Unicode для обработки (UTF-16 или UTF-32) и UTF-8 для обмена данными (связь, хранение).

Если все пользовательские API используют UTF-16 (например, в Windows), то ваши строки как UTF-8 означают, что вам нужно будет преобразовать все входные данные в UTF-16, вызвать Win API, а затем преобразовать ответ в UTF -8. Очень боль.

Но если главной проблемой является пользовательский интерфейс, то строки являются простой проблемой. Более сложным является структура пользовательского интерфейса. И для этого я бы рекомендовал wxWidgets (http://www.wxWidgets.org). Поддерживает многие платформы, зрелые (17 лет и все еще очень активные), собственные виджеты, Unicode, либеральная лицензия.

Ответ 5

Я бы пошел на представление UTF16 в памяти и UTF-8 или 16 на жесткий диск или провод. Основная причина: UTF16 имеет фиксированный размер для каждой "буквы". Это упрощает много обязанностей при работе со строкой (серификация, замена частей,...).

Единственная причина для UTF-8 - сокращение использования памяти для "западных/латинских" букв. Вы можете использовать это представление для хранения диска или транспортировки по сети. Он также имеет преимущество, которое вам не нужно беспокоиться о байтовом порядке при загрузке/сохранении на диск/провод.

С учетом этих причин я бы пошел на std:: wstring внутри, или - если ваша библиотека GUI предлагает Widestring, используйте это (например, QString из QT). И для хранения дисков я бы написал небольшую платформу, независимую от оболочки для платформы api. Или я бы посмотрел unicode.org, если у них есть независимый от платформы код, доступный для этого преобразования.


для пояснения: корейские/японские буквы НЕ западные/латинские. Японцы выступают за кандзи. Вот почему я упомянул латинский набор символов.


для UTF-16 не 1 символ /2 байта. Это предположение верно только для символов, находящихся на базовой многоязычной плоскости (см. http://en.wikipedia.org/wiki/UTF16). Однако большинство пользователей UTF-16 предполагают, что все символы находятся на BMP. Если это не может быть гарантировано для вашего приложения, вы можете переключиться на UTF32 или переключиться на UTF8.

Все еще UTF-16 используется по причинам, упомянутым выше во многих API-интерфейсах (например, Windows, QT, Java,.NET, wxWidgets)