Каков оптимальный мультиплатформенный способ работы со строками Unicode в C ++? - PullRequest
18 голосов
/ 10 января 2010

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

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

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

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

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

Смежные вопросы:

Ответы [ 5 ]

7 голосов
/ 10 января 2010

Я бы настоятельно рекомендовал использовать 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);
5 голосов
/ 10 января 2010

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

2 голосов
/ 10 января 2010

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

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

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

1 голос
/ 11 января 2010

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

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

Учитывая эти причины, я бы выбрал внутренний std :: wstring или - если ваша библиотека графического интерфейса предлагает 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)

1 голос
/ 11 января 2010

Практическое правило: используйте форму 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, либеральную лицензию.

...