Как делают я получаю станд. STL:: представить в виде строки для работы с unicode на окнах?

В моей компании у нас есть кросс-платформенная библиотека (Linux & Windows), которая содержит наше собственное расширение станд. STL:: строка, этот класс обеспечивает весь вид функциональности сверху строки; разделение, формат, к/от base64, и т.д. Недавно нам дали требование создания этой строки unicode "дружественный" в основном, это должно поддерживать символы с китайского, японского, арабского языка, и т.д. После начального исследования это кажется прекрасным на стороне Linux, так как каждой вещью является по сути UTF-8, однако я испытываю затруднения из-за стороны Windows; есть ли прием к получению станд. STL:: представить в виде строки для работы UTF-8 на окнах? Это даже возможно? Существует ли лучший путь? Идеально мы сохранили бы нас на основе станд.:: строка начиная с того, на основе именно это строковый класс в Linux.

Спасибо,

9
задан hippietrail 30 March 2011 в 13:17
поделиться

7 ответов

В вашем вопросе есть несколько заблуждений.

  • Ни C ++, ни STL не работают с кодировками.

  • std :: string по сути представляет собой строку из байтов , а не символов . Так что у вас не должно возникнуть проблем с добавлением в него Unicode в кодировке UTF-8. Однако имейте в виду, что все функции string также работают с байтами, поэтому myString.length () даст вам количество байтов, а не количество символов.

  • Linux - это , а не по своей сути UTF-8. В настоящее время большинство дистрибутивов по умолчанию используют UTF-8, но на него не следует полагаться.

12
ответ дан 4 December 2019 в 06:29
поделиться

Помещение точек кода UTF-8 в std::string должно быть в порядке независимо от платформы. Проблема на Windows заключается в том, что почти ничто другое не ожидает и не работает с UTF-8 - вместо этого ожидается и работает UTF-16. Вы можете перейти на std::wstring, который будет хранить UTF-16 (по крайней мере, в большинстве компиляторов Windows), или вы можете написать другие процедуры, которые будут принимать UTF-8 (вероятно, конвертируя в UTF-16, а затем передавая в ОС).

7
ответ дан 4 December 2019 в 06:29
поделиться

Вы смотрели на std::wstring? Это версия std::basic_string для wchar_t, а не char, который использует std::string.

4
ответ дан 4 December 2019 в 06:29
поделиться

Нет, нет способа заставить Windows рассматривать "узко" "строки в формате UTF-8.

Вот что лучше всего подходит для меня в этой ситуации (кроссплатформенное приложение, имеющее сборки для Windows и Linux).

  • Используйте std :: string в кроссплатформенной части кода. Предположим, что он всегда содержит строки UTF-8.
  • В части кода Windows явно используйте «широкие» версии Windows API, т.е. напишите, например, CreateFileW вместо CreateFile. Это позволяет избежать зависимости от конфигурации системы сборки.
  • На уровне абстракции platfrom конвертируйте между UTF-8 и UTF-16, где это необходимо (MultiByteToWideChar / WideCharToMultiByte).

Другие подходы, которые я пробовал, но которые мне не очень нравятся:

  • typedef std :: basic_string tstring; затем используйте tstring в бизнес-коде. Можно сделать обертки / перегрузки, чтобы упростить преобразование между std :: string и std :: tstring, но это по-прежнему добавляет много боли.
  • Используйте везде std :: wstring . Это не очень помогает, поскольку wchar_t является 16-битным в Windows, поэтому вам придется либо ограничиться BMP, либо пойти на множество сложностей, чтобы сделать код, работающий с Unicode, кроссплатформенным. В последнем случае все преимущества перед UTF-8 улетучиваются.
  • Используйте ATL / WTL / MFC CString в части, специфичной для платформы; используйте std :: string в части cross-platfrom. На самом деле это вариант того, что я рекомендую выше. CString во многих аспектах превосходит std :: string (на мой взгляд). Но он вводит дополнительную зависимость и поэтому не всегда приемлем или удобен.
2
ответ дан 4 December 2019 в 06:29
поделиться

Да - за счет более глубокого понимания локалей и кодировок.

В Windows есть два вызова функций для всего, что требует текста: FoobarA() и FoobarW(). Функции *W() принимают строки в кодировке UTF-16, а *A() - строки в текущей кодовой странице. Однако Windows не поддерживает кодовую страницу UTF-8, поэтому вы не можете напрямую использовать ее в этом смысле с функциями *A(), да и не стоит полагаться на то, что она будет установлена пользователями. Если вам нужен "Юникод" в Windows, используйте функции с поддержкой Юникода (*W). Существуют учебные пособия, набрав в Google "Unicode Windows tutorial", вы найдете несколько.

Если вы храните данные в формате UTF-8 в строке std::string, то перед тем, как передать их в Windows, преобразуйте их в UTF-16 (Windows предоставляет функции для этого), а затем передайте их в Windows.

Многие из этих проблем возникают из-за того, что C/C++ в целом не зависит от кодировки. char на самом деле не является символом, это просто интегральный тип. Даже использование массивов char для хранения данных UTF-8 может привести к проблемам, если вам нужно получить доступ к отдельным единицам кода, поскольку знаковость char не определена стандартами. Утверждение типа str[x] < 0x80 для проверки на наличие многобайтовых символов может быстро привести к ошибке. (Это утверждение всегда верно, если char является знаковым.) Кодовая единица UTF-8 - это беззнаковый интегральный тип с диапазоном 0-255. Это в точности соответствует типу uint8_t в языке Си, хотя unsigned char тоже работает. Идеально было бы сделать строку UTF-8 массивом uint8_t, но из-за старых API это делается редко.

Некоторые люди рекомендуют wchar_t, утверждая, что это "тип символов Unicode" или что-то в этом роде. Опять же, здесь стандарт столь же агностичен, как и раньше, поскольку C предназначен для работы везде, а везде может не использоваться Unicode. Таким образом, wchar_t не более Unicode, чем char. Стандарт гласит:

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

В Linux, wchat_t представляет собой единицу кода / кодовую точку UTF-32. Его размер составляет 4 байта. Однако в Windows это единица кода UTF-16, и ее размер составляет всего 2 байта. (Я бы сказал, что это не соответствует вышесказанному, так как 2 байта не могут представлять весь Юникод, но так оно и есть). Такая разница в размере и разница в кодировке данных явно затрудняет переносимость. Сам стандарт Unicode рекомендует отказаться от wchar_t, если вам нужна переносимость. (§5.2)

Конечный урок: Мне проще всего хранить все свои данные в каком-то хорошо объявленном формате. (Обычно UTF-8, обычно в std::string's, но мне бы очень хотелось чего-то получше). Здесь важна не часть UTF-8, а то, что я знаю, что мои строки - UTF-8. Если я передаю их другому API, я также должен знать, что этот API ожидает строк UTF-8. Если это не так, то я должен их преобразовать. (Таким образом, если я обращаюсь к API Window, я должен сначала преобразовать строки в UTF-16.) Текстовая строка UTF-8 - это "апельсин", а текстовая строка "latin1" - это "яблоко". Массив char, который не знает, в какой кодировке он находится, - это рецепт катастрофы.

9
ответ дан 4 December 2019 в 06:29
поделиться

Если вы хотите избежать головной боли, не используйте строковые типы STL вообще. C++ ничего не знает о Unicode или кодировках, поэтому для переносимости лучше использовать библиотеку, приспособленную для поддержки Unicode, например, библиотеку ICU. ICU использует строки UTF-16 по умолчанию, поэтому преобразование не требуется, и поддерживает преобразование во многие другие важные кодировки, такие как UTF-8. Также старайтесь использовать кроссплатформенные библиотеки типа Boost.Filesystem для таких вещей, как работа с путями (boost::wpath). Избегайте std::string и std::fstream.

2
ответ дан 4 December 2019 в 06:29
поделиться

В Windows API и библиотеке времени выполнения C, char* параметры интерпретируются как закодированные в кодовой странице "ANSI". Проблема в том, что UTF-8 не поддерживается как кодовая страница ANSI, что меня невероятно раздражает.

Я нахожусь в похожей ситуации, занимаясь переносом программного обеспечения с Windows на Linux и одновременно делая его поддерживающим Unicode. Мы применили следующий подход:

  • Использовать UTF-8 в качестве кодировки по умолчанию для строк.
  • В коде, специфичном для Windows, всегда вызывать "W" версию функций, преобразуя строковые аргументы между UTF-8 и UTF-16 по мере необходимости.

Это также подход, принятый в Poco.

1
ответ дан 4 December 2019 в 06:29
поделиться
Другие вопросы по тегам:

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