UNICODE, UTF-8 и Windows mess

Я пытаюсь реализовать текстовую поддержку в Windows с намерением позже перейти на платформу Linux. Было бы идеально поддерживать международные языки в унифицированном виде, но это, похоже, нелегко выполнить при рассмотрении обеих рассматриваемых платформ. Я потратил значительное количество времени на чтение UNICODE, UTF-8 (и других кодировок), широкоформатных и т.д., И вот что я понял до сих пор:

UNICODE, как стандарт, описывает набор символов, которые могут отображаться, и порядок, в котором они происходят. Я называю это "что": UNICODE указывает, что будет доступно.

UTF-8 (и другие кодировки) определяют, как: как каждый символ будет представлен в двоичном формате.

Теперь, в Windows, они первоначально выбрали кодировку UCS-2, но это не соответствовало требованиям, поэтому UTF-16 - это то, что у них есть, что также является multi- char при необходимости.

Итак, вот делемма:

  • Windows внутри только UTF-16, поэтому, если вы хотите поддерживать международные символы, вам необходимо преобразовать их в свои широкоформатные версии, чтобы соответствующим образом использовать вызовы ОС. Кажется, что нет никакой поддержки для вызова чего-то типа CreateFileA() с многобайтовой строкой UTF-8, и она выглядит правильно. Правильно ли это?
  • В C есть несколько многобайтовых поддерживающих функций (_mbscat, _mbscpy и т.д.), однако в окнах тип символа определяется как unsigned char * для этих функций. Учитывая тот факт, что ряд функций _mbs не является полным набором (т.е. Нет _mbstol для преобразования многобайтовой строки в длинную, например), вы вынуждены использовать некоторые версии char * среды выполнения функции, что приводит к проблемам с компилятором из-за разницы между подписанными/неподписанными типами этих функций. Кто-нибудь даже использует их? Вы просто делаете большую кучу кастингов, чтобы обойти ошибки?
  • В С++ std::string имеет итераторы, но они основаны на char_type, а не на кодовых точках. Поэтому, если я делаю a ++ на std::string:: iterator, я получаю следующий символ char_type, а не следующий код. Аналогично, если вы вызываете std::string:: operator [], вы получаете ссылку на char_type, который имеет большой потенциал, чтобы не быть полной точкой кода. Итак, как один из них перебирает std::string по кодовой точке? (C имеет функцию _mbsinc()).

Ответ 1

  • Правильно. Вы будете конвертировать UTF-8 в UTF-16 для вызовов Windows API.

  • В большинстве случаев вы будете использовать регулярные строковые функции для UTF-8 - strlen, strcpy (ick), snprintf, strtol. Они отлично справятся с символами UTF-8. Либо используйте char * для UTF-8, либо вам нужно будет все бросить.

    Обратите внимание, что версии подчеркивания типа _mbstowcs не являются стандартными, они обычно называются без подчеркивания, например mbstowcs.

  • Трудно найти примеры, в которых вы действительно хотите использовать operator[] в строке Unicode, мой совет - держаться подальше от него. Аналогично, итерация по строке имеет удивительно малое применение:

    • Если вы разбираете строку (например, строка является кодом C или JavaScript, возможно, вам нужен синтаксис hilighting), тогда вы можете выполнять большую часть работы побайтно и игнорировать многобайтовый аспект.

    • Если вы выполняете поиск, вы также будете делать это побайтно (но не забудьте сначала нормализовать).

    • Если вы ищете разрывы слов или границы графема графства, вы захотите использовать библиотеку, такую ​​как ICU. Алгоритм не прост.

    • Наконец, вы всегда можете преобразовать кусок текста в UTF-32 и работать с ним таким образом. Я думаю, что это самый надежный вариант, если вы реализуете любой из алгоритмов Unicode, например, сортировку или нарушение.

    Смотрите: С++ повторите или разделите строку UTF-8 на массив символов?

Ответ 2

Просто сделайте UTF-8

В каждом plaftorm имеется множество библиотек поддержки для UTF-8, также некоторые из них - multaftorm. API UTF-16 в Win32 ограничены и непоследовательны, как вы уже отметили, поэтому лучше сохранить все в UTF-8 и конвертировать в UTF-16 в последний момент. Есть также некоторые удобные обертки UTF-8 для API окон.

Кроме того, в документах уровня приложения UTF-8 становится все более и более приемлемым в качестве стандарта. Каждое приложение для обработки текста либо принимает UTF-8, либо в худшем случае показывает его как "ASCII с некоторыми дингбатами", в то время как только несколько приложений, которые поддерживают документы UTF-16, и те, которые этого не делают, показывают его как "лоты и лоты" пробелов! "

Ответ 3

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

Да, это правильно. Варианты функций *A интерпретируют строковые параметры в соответствии с текущей активной кодовой страницей (которая является Windows-1252 на большинстве компьютеров в США и Западной Европе, но часто могут быть другими кодовыми страницами) и конвертировать их в UTF-16. Существует кодовая страница UTF-8, однако AFAIK не может программно установить активную кодовую страницу (там GetACP, чтобы получить активную кодовую страницу, но не соответствующую SetACP).

  • В C есть несколько многобайтовых поддерживающих функций (_mbscat, _mbscpy и т.д.), однако в окнах тип символа определяется как unsigned char * для этих функций. Учитывая тот факт, что ряд функций _mbs не является полным набором (т.е. Нет _mbstol для преобразования многобайтовой строки в длинную, например), вы вынуждены использовать некоторые версии char * среды выполнения функции, что приводит к проблемам с компилятором из-за разницы между подписанными/неподписанными типами этих функций. Кто-нибудь даже использует их? Вы просто делаете большую кучу кастингов, чтобы обойти ошибки?

Семейство функций mbs* почти никогда не используется, по моему опыту. За исключением mbstowcs, mbsrtowcs и mbsinit, эти функции не являются стандартными C.

  • В С++ std::string имеет итераторы, но они основаны на char_type, а не на кодовых точках. Поэтому, если я делаю a ++ на std::string:: iterator, я получаю следующий символ char_type, а не следующий код. Аналогично, если вы вызываете std::string:: operator [], вы получаете ссылку на char_type, который имеет большой потенциал, чтобы не быть полной точкой кода. Итак, как один из них перебирает std::string по кодовой точке? (C имеет функцию _mbsinc()).

Я думаю, что mbrtowc(3) будет лучшим вариантом для декодирования одиночной кодовой точки многобайтовой строки.

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