В моей компании у нас есть кросс-платформенная библиотека (Linux & Windows), которая содержит наше собственное расширение станд. STL:: строка, этот класс обеспечивает весь вид функциональности сверху строки; разделение, формат, к/от base64, и т.д. Недавно нам дали требование создания этой строки unicode "дружественный" в основном, это должно поддерживать символы с китайского, японского, арабского языка, и т.д. После начального исследования это кажется прекрасным на стороне Linux, так как каждой вещью является по сути UTF-8, однако я испытываю затруднения из-за стороны Windows; есть ли прием к получению станд. STL:: представить в виде строки для работы UTF-8 на окнах? Это даже возможно? Существует ли лучший путь? Идеально мы сохранили бы нас на основе станд.:: строка начиная с того, на основе именно это строковый класс в Linux.
Спасибо,
В вашем вопросе есть несколько заблуждений.
Ни C ++, ни STL не работают с кодировками.
std :: string
по сути представляет собой строку из байтов , а не символов . Так что у вас не должно возникнуть проблем с добавлением в него Unicode в кодировке UTF-8. Однако имейте в виду, что все функции string
также работают с байтами, поэтому myString.length ()
даст вам количество байтов, а не количество символов.
Linux - это , а не по своей сути UTF-8. В настоящее время большинство дистрибутивов по умолчанию используют UTF-8, но на него не следует полагаться.
Помещение точек кода UTF-8 в std::string
должно быть в порядке независимо от платформы. Проблема на Windows заключается в том, что почти ничто другое не ожидает и не работает с UTF-8 - вместо этого ожидается и работает UTF-16. Вы можете перейти на std::wstring
, который будет хранить UTF-16 (по крайней мере, в большинстве компиляторов Windows), или вы можете написать другие процедуры, которые будут принимать UTF-8 (вероятно, конвертируя в UTF-16, а затем передавая в ОС).
Вы смотрели на std::wstring
? Это версия std::basic_string
для wchar_t
, а не char
, который использует std::string
.
Нет, нет способа заставить Windows рассматривать "узко" "строки в формате UTF-8.
Вот что лучше всего подходит для меня в этой ситуации (кроссплатформенное приложение, имеющее сборки для Windows и Linux).
Другие подходы, которые я пробовал, но которые мне не очень нравятся:
typedef std :: basic_string tstring;
затем используйте tstring в бизнес-коде. Можно сделать обертки / перегрузки, чтобы упростить преобразование между std :: string и std :: tstring, но это по-прежнему добавляет много боли. std :: wstring
. Это не очень помогает, поскольку wchar_t
является 16-битным в Windows, поэтому вам придется либо ограничиться BMP, либо пойти на множество сложностей, чтобы сделать код, работающий с Unicode, кроссплатформенным. В последнем случае все преимущества перед UTF-8 улетучиваются. CString
в части, специфичной для платформы; используйте std :: string
в части cross-platfrom. На самом деле это вариант того, что я рекомендую выше. CString
во многих аспектах превосходит std :: string
(на мой взгляд). Но он вводит дополнительную зависимость и поэтому не всегда приемлем или удобен. Да - за счет более глубокого понимания локалей и кодировок.
В 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
, который не знает, в какой кодировке он находится, - это рецепт катастрофы.
Если вы хотите избежать головной боли, не используйте строковые типы STL вообще. C++ ничего не знает о Unicode или кодировках, поэтому для переносимости лучше использовать библиотеку, приспособленную для поддержки Unicode, например, библиотеку ICU. ICU использует строки UTF-16 по умолчанию, поэтому преобразование не требуется, и поддерживает преобразование во многие другие важные кодировки, такие как UTF-8. Также старайтесь использовать кроссплатформенные библиотеки типа Boost.Filesystem для таких вещей, как работа с путями (boost::wpath
). Избегайте std::string
и std::fstream
.
В Windows API и библиотеке времени выполнения C, char*
параметры интерпретируются как закодированные в кодовой странице "ANSI". Проблема в том, что UTF-8 не поддерживается как кодовая страница ANSI, что меня невероятно раздражает.
Я нахожусь в похожей ситуации, занимаясь переносом программного обеспечения с Windows на Linux и одновременно делая его поддерживающим Unicode. Мы применили следующий подход:
Это также подход, принятый в Poco.