Функции мультибайтных строк

Содержание

Функции мультибайтных строк

Cледующие функции обеспечивают работу со строками с завершающим нулем:

Функции работы со строками с завершающим нулем.
Функция Описание
AnsiStrComp Сравнивает две строки с завершающим нулем.
AnsiStrIComp Сравнивает две строки с завершающим нулем без учета регистра.
AnsiStrLComp Сравнивает первые MaxLen байт двух строк с завершающим нулем, с учетом регистра.
AnsiStrLIComp Сравнивает первые MaxLen байт двух строк с завершающим нулем, без учета регистра.
AnsiStrLower Переводит все символы строки с завершающим нулем в нижний регистр.
AnsiStrPos Возвращает указатель на первое вхождение заданной подстроки в строку.
AnsiStrRScan Возвращает указатель на последнее вхождение заданного символа в строку.
AnsiStrScan Возвращает указатель на первое вхождение заданного символа в строку.
AnsiStrUpper Переводит все символы строки с завершающим нулем в верхний регистр.
ExtractStringth Заполняет список (массив) строк подстроками, из строки с завершающим нулем, которые отделены друг от друга разделителями.
LineStart Ищет конец последней полной строки (знак перевода каретки) в буффере.
SearchBuf Находит подстроку внутри текстового буфера.
StrAlloc Выделяет память под символьный буфер, заданного размера, в «куче» .
StrBufSize Возвращает размер символьного буфера, выделенного при помощи StrAlloc или StrNew.
StrCat Соединяет две строки в одну.
StrComp Сравнивает две строки между собой.
StrCopy Копирует строку.
StrDispose Освобождает символьный буфер, выделенный при помощи StrAlloc или StrNew.
StrECopy Копирует строку и возвращает указатель на коец строки.
StrEnd Возвращает указатель на конец строки.
StrFmt Форматирует одно или более значений в строке.
StrIComp Сравнивает две строки без учета регистра.
StrLCat Соединяет две строки в одну результирующую строку, с заданной максимальной длинной.
StrLComp Сравнивает две строки на заданной максимальной длине.
StrLCopy Копирует строку до заданной максимальной длины.
StrLen Возвращает длину строки.
StrLFmt Форматирует одно или более значений в строке на заданной максимальной длине.
StrLIComp Сравнивает две строки на заданной максимальной длине без учета регистра.
StrLower Переводит строку в нижний регистр.
StrMove Переносит блок символов из одной строки в другую.
StrNew Помещает строку в «кучу».
StrPCopy Копирует строку AnsiString (длинную строку Paskal) в строку с завершающим нулем.
StrPLCopy Копирует строку AnsiString (длинную строку Paskal) в строку с завершающим нулем с заданной максимальной длиной.
StrPos Возвращает указатель на первое вхождение заданной подстроки в строку.
StrRScan Возвращает указатель на последнее вхождение заданного символа в строку.
StrScan Возвращает указатель на первое вхождение заданного символа в строку.
StrUpper Переводит строку в верхний регистр.

В Delphi имеется тип PChar , представляющий так называемую строку с завершающим нулем. Строки с завершающим нулем не содержат байтов длины. В отличие от обычных строк (см. Функции работы со строками.) они состоят из последовательности ненулевых символов, за которым следует символ NULL (#0). Никаких ограничений на длину строк с завершающим нулем не накладывается. Фактически он указывает на символ

При работе со строками с завершающим нулем целесообразно использовать расширенный синтаксис языка Delphi, который задается компилятору директивой (хотя ее можно не указывать в начале программы, т.к. она устанавливается по умолчанию). Расширенный синтаксис позволяет использовать особые правила для стандартного типа PChar и массивов с нулевым индексом. В частности стандартные процедуры Read, ReadLn, Str и Val могут быть использованы с такими массивами, а процедуры Write, WriteLn, Val, AssignFile и Rename могут применяться как с массивами, так и с символьными указателями.

Расширенный синтаксис позволяет ставить в соответствие строкам с завершающим нулем символьный массив типа

где X — положительное число типа Integer , определяющее количество символов в строке, не считая завершающего символа с кодом 0. В отличие от типа String , символ с индексом 0 здесь является первым символом строки, а последний символ с индексом X — завершающим символом с кодом 0.

Стандартные функции работы со стандартными строками имеют аналоги для работы с мультибайтными строками (AnsiString), которые к тому же обеспечивают прядок сортировки символов в соответствии с установками национального алфавита. В типе AnsiString символы кодируются в коде ANSI. Имена мультибайтных функций начинаются с Ansi-. Например, мультибайтная версия функции StrPos будет AnsiStrPos. Поддержка мультибайтных символов зависит от оперативной системы и базируется на ее текущей локализации.

Список литературы:

  1. Гофман В.Э., Хомоненко А.Д. Delphi 6. — СПб. БХВ-Петербург, 2002. — 1152 с.: ил.
  2. Турбо Паскаль 7.0 — К. Торгово-издательское бюро BHV, 1996 — 448 с.: ил.
  3. Delphi7 Help

Arduino — функции — биты и байты

Arduino IDE располагает набором функций, позволяющих выполнять операции на битах и байтах. Можно прочитать значение бита или установить его.

Функции highByte() и lowByte()

Функции highByte() и lowByte() позволяют извлекать старший и младший байт соответственно из сохраненного значения. Если мы объявим переменную как int, ее значение будет храниться в двух байтах. Отправка этого значения через последовательный порт требует отправки старшего и младшего байта.

Функция lowByte() даст нам значение младшего байта, тогда как значение highByte() — старшего байта. Синтаксис команд следующий:

Мы вызываем функции с параметром, который является «большим» (многобайтным), но получаем один байт. Здесь возникает вопрос, что вернет функция в случае, когда в качестве параметра передадим четырехбайтную переменную?

Фактически, функции позволяют нам указывать самый старший и самый младший байт. Это означает, что для четырехбайтового числа мы получим первый или четвертый байт. Второй и третий байт напрямую не доступны. Ниже приведен пример использования функций highByte() и lowByte():

Функции bitRead() и bitWrite()

Функция bitRead() позволяет прочитать значение определенного бита в указанной переменной. Мы вызываем ее с двумя параметрами. Первый из них — это имя переменной, значение бита которой мы хотим получить, второй — номер бита для чтения.
Отсчет всегда от нуля, то есть у нас есть бит нулевой, первый, второй и т. д. Функция возвращает значение LOW или HIGH.

Функция bitWrite() позволяет записать определенный бит. Вызывается с тремя параметрами, первый из них — это переменная, второй — это номер бита, а третий — это информация о том, что бит необходимо установить (HIGH) или сбросить (LOW). Примеры использования bitRead() и bitWrite():

Битовые операции часто используются во время программирования для установки или считывания состояния регистров или выводов на основе сохраненных или переданных данных.

Функции bitSet() и bitClear()

Альтернативным способом изменения состояния (значения) бита для функции bitWrite() — функции bitSet() и bitClear(). В функции bitWrite() в качестве параметра мы задаем установить или сбросить бит. Используя одну из функций bitSet () или bitClear (), мы явно определяем, хотим ли мы, чтобы бит был установлен или сброшен. Вот несколько примеров использования функций bitSet () и bitClear ():

Функция bit()

Функция бит () вычисляет значение указанного бита. Ниже примеры:

Строковые функции PHP Multibyte (mb_string)

В то время как есть много языков, в которых каждый необходимый символ может быть представлен взаимно-однозначным отображением к значению на 8 битов, есть также несколько языков, которые требуют ,большего числа символов для письменной связи, которая не может содержаться в пределах одного байта. Многобайтовая кодировка символов была разработана для работы с более чем 256 символами в правильной bytewise кодировке.

Когда Вы управляете строками (вырезка, разбивание, соединение, и т.д.) , закодированных в многобайтовом кодировании, Вы должны использовать специальные функции, так как два или больше последовательных байта могут представить единственный(отдельный) символ в таких схемах кодирования. Иначе, если Вы применяете однобайтовую строковую функцию к строке, созданной из многобайтовых символов, функция будет не в состоянии обнаруживать начало или окончание многобайтовых символов.

mbstring обеспечивает эти многобайтовые определенные строковые функции, которые помогают Вам иметь дело с многобайтовым кодированием в PHP, который, как предполагается, используется с единственным(отдельным) кодированием байта. В дополнение к этому, mbstring обрабатывает символ, кодирующий преобразование между возможными парами кодирования.

mbstring также предназначен, чтобы обработать кодирование на основе UTF-8 и UCS-2 и других (смотрите ниже), так как mbstring был первоначально разработан для использования в японских web-страницах.

Требования Кодировки Символов PHP4

  • побайтное кодирование
  • однобайтные символы находятся в диапазоне 00h-7fh, что совместимо с ASCII
  • многобайтное кодирование — вне диапазона 00h-7fh

Вот примеры внутренней кодировки символов, которые работают и НЕ работают с PHP.

Кодировки символов, не работающие с PHP, могут быть конвертированы с помощью функции конвертации HTTP-ввода/вывода модуля mbstring.

Примечание: SJIS не должна использоваться для внутреннего кодирования, если читатель не знаком достаточно хорошо с вопросами работы разборщика/компилятора и кодирования символов.

Примечание: Если вы используете БД с PHP, рекомендуется использовать одну кодировку для БД и internal encoding/внутреннего кодирования для облегчения использования и повышения производительности.

Если вы используете PostgreSQL, он поддерживает кодировки символов, которые отличаются от backend-кодировки. См. детали в учебнике PostgreSQL.

Как подключить mbstring

mbstring это модуль расширения. Вам необходимо подключить его скриптом configure.

Следующие опции конфигурации имеют отношение к модулю mbstring:

  • —enable-mbstring : включает функции mbstring. Эта опция нужна для использования mbstring-функций.
  • —enable-mbstr-enc-trans : включает конвертацию кодировки символов HTTP-ввода с использованием mbstring-машины конвертации. Если эта возможность включена, кодировка символов HTTP-ввода может быть автоматически конвертирована в mbstring.internal_encoding.

HTTP ввод и вывод

Конвертация кодировки символов HTTP-ввода/вывода может конвертировать также двоичные данные. Пользователям предлагается контролировать конвертацию кодировки символов, если бинарные данные используются для ввода/вывода HTTP.

Если enctype для HTML-формы установлен multipart/form-data, mbstring не конвертирует кодировку символов в POST-данных. Если это так, строки должны конвертироваться во внутреннюю кодировку символов.

Нет способов управлять конвертацией символов HTTP-ввода из PHP-скрипта. Отключение конвертации символов HTTP-ввода нужно сделать в php.ini.

Отключение конвертации символов HTTP-ввода в php.ini

При использовании PHP как Apache-модуля можно переопределять PHP ini-установку на уровне Virtual Host в httpd.conf или на уровне директории в .htaccess. Обратитесь к разделу Конфигурация и учебнику Apache.

Есть несколько способов включить конвертацию кодировки символов вывода. Один — это использование php.ini, другой — функция ob_start с mb_output_handler как ob_start callback-функция.

Примечание: Для пользователей PHP3-i18n: конвертация вывода mbstring отличается от PHP3-i18n. Кодировка символов конвертируется с использованием буфера вывода.

Установки php.ini

Пример скрипта

Поддерживаемые кодировки символов

В настоящее время модуль mbstring поддерживает нижеследующие кодировки символов. Кодировка символов может быть специфицирована параметром encoding функций модуля mbstring.

Кодировки, поддерживаемые данным расширением PHP:

UCS-4, UCS-4BE, UCS-4LE, UCS-2, UCS-2BE, UCS-2LE, UTF-32, UTF-32BE, UTF-32LE, UCS-2LE, UTF-16, UTF-16BE, UTF-16LE, UTF-8, UTF-7, ASCII, EUC-JP, SJIS, eucJP-win, SJIS-win, ISO-2022-JP, JIS, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10, ISO-8859-13, ISO-8859-14, ISO-8859-15, byte2be, byte2le, byte4be, byte4le, BASE64, 7bit, 8bit и UTF7-IMAP.

Вхождение в php.ini, принимающее имя кодировки, принимает также «auto» и «pass».
mbstring функции, принимающие имя кодировки, принимают и «auto».

Если «pass» установлено, никакая конвертация кодировки символов не выполняется.

Если «auto» установлено, оно расширяется до «ASCII,JIS,UTF-8,EUC-JP,SJIS».

Примечание: «Поддерживаемые кодировки символов» не означает, что это работает как внутренний код символа.

Директива Значение по умолчанию
mbstring.language «neutral»
mbstring.detect_order NULL
mbstring.http_input «pass»
mbstring.http_output «pass»
mbstring.internal_encoding NULL
mbstring.script_encoding NULL
mbstring.substitute_character NULL
mbstring.func_overload «0»
mbstring.encoding_translation «0»
  • mbstring.internal_encoding определяет внутреннюю кодировку символов по умолчанию
  • mbstring.http_input определяет кодировку символов по умолчанию HTTP-ввода
  • mbstring.http_output определяет кодировку символов по умолчанию HTTP-вывода
  • mbstring.detect_order определяет порядок определения кодировки символов по умолчанию. См. также mb_detect_order
  • mbstring.substitute_character определяет символы для замещения неправильных кодировок символов

Web-браузерам предлагается использовать ту же кодировку при отправку форм. Однако браузеры могут не использовать ту же кодировку символов. См. mb_http_input для определения кодировки браузера.

Если enctype имеет установленное значение multipart/form-data в HTML-формах, mbstring не конвертирует кодировку символов в POST-данных. Пользователь обязан сделать это в скрипте, если конвертация нужна.

Одновременно браузеры достаточно наворочены, чтобы определять кодировку символов в HTML. charset лучше установить в HTTP-шапке/header. Измените default_charset в соответствии с кодировкой символов.

Установки php.ini

Установки php.ini для пользователей EUC-JP

Установки php.ini для пользователей SJIS

Перегрузка/Overload строковых функций PHP mbstring-функциями с поддержкой многобайтных символов

Поскольку большинство приложений PHP написаны на языках, использующих однобайтную кодировку символов, имеются некоторые трудности при работе с многобайтными строками, в том числе с японскими. Большинство строковых PHP-функций, таких как substr, не поддерживают многобайтные строки.

Многобайтное расширение (mbstring) имеет строковые РНР-функции с поддержкой многобайтных символов (например, substr() поддерживает mb_substr).

Многобайтное расширение (mbstring) также поддерживает ‘перегрузку функций’ для добавления функциональности многобайтных строк без модификации кода. Используя перегрузку функций, некоторые строковые функции PHP будут перегружены многобайтными строковыми функциями. Например, mb_substr вызывается вместо substr, если перегрузка функций включена. Перегрузка функций облегчает перенос приложений, поддерживая только однобайтные кодировки для многобайтных приложений.

mbstring.func_overload в php.ini должно иметь некоторое положительное значение для использования перегрузки функций. Это значение должно специфицировать категорию перегружающей функции: 1 включает перегрузку функции mail; 2 — строковые функции, 4 — функции регулярных выражений. Например, если установлена 7, mail, strings и regex функции должны перегружаться. Список перегружаемых функций дан в таблице.

значение mbstring.func_overload функция-оригинал перегруженная функция
1 mail mb_send_mail
2 strlen mb_strlen
2 strpos mb_strpos
2 strrpos mb_strrpos
2 substr mb_substr
4 ereg mb_ereg
4 eregi mb_eregi
4 ereg_replace mb_ereg_replace
4 eregi_replace mb_eregi_replace
4 split mb_split

Основы многобайтной японской кодировки символов

Большинство японских символов для своего представления требуют более одного байта на символ. Кроме того, в японском окружении используются разные схемы кодировки. Существуют кодировки EUC-JP, Shift_JIS(SJIS) и ISO-2022-JP(JIS). По мере приобретения популярности Unicode начинает использоваться также UTF-8. при разработке Web-приложений для японской среды важно использовать набор символов, соответствующих текущей задаче — HTTP ввод/вывод, RDBMS и E-mail.

  • Для хранения символа можно использовать до 6 байтов.
  • Многобайтный символ обычно в два раза шире однобайтного. Более широкие символы называются «zen-kaku» — что означает «полная ширина», более узкие называются «han-kaku» — что означает «половина ширины». «zen-kaku» имеют обычно фиксированную ширину.
  • Некоторые кодировки определяют shift(escape)-последовательность для входа/выхода в/из многобайтных строк.
  • ISO-2022-JP обязан использоваться для SMTP/NNTP.
  • «i-mode» web-сайт предполагается использовать с SJIS.

Как считать символ с мультибайтовой строки?

Есть мультибайтовая строка, длина её меряется в мегабайтах, нужно считывать в цикле посимвольно, как считать один символ с мультибайтовой строки?(не используя uchar.h)

2 ответа 2

Берем очередной байт из строки. Предполагая, что это первый байт utf-8 символа

Если символ длиной более 1 байта, то все последующие байты символа должны быть в диапазоне b>=0x80 && b

Написал по стандарту RFC3629, надеюсь нигде не ошибся. Можно еще посмотреть код готовых библиотек.

Эх. Обожаю делать велосипеды, вот накидал пример, с разбором кодов символов. Получаемые коды для русских букв сверил с выдаваемых функцией Javascript charCodeAt — совпали. Внимание: собрано на коленке. нет проверок, что строка закончилась в середине символа, при неправильной unicode строке возможен выход за пределы массива ! Трехбайтные и четырехбайтные символы так же не проверены, т.к. не знаю китайского. Так же нет проверки 2го и последующего байта unicode на корректность, тупо сбрасываем старшие 2 бита и используем.

Универсальный способ получения длины текущего символа:

Чем определить кол-во байт необходимое для хранения мультибайтной строки

Чем, в условиях только libc, можно определить кол-во памяти необходимое для хранения строки в мультибайтной кодировке (имея wchar_t-строку).

Перемещено Aceler из linux-org-ru

А если я оставлю комент в ЛОР, а потом топик перенесут в Development, мне защитают скор?

Ты ошибся разделом.

strlen, или sizeof. Что-то из этих двух должно подойти

Нет. Теперь можно написать что-нибудь по теме и засчитают.

wcstombs() с NULL в первом параметре вернёт длину в мультибайтной кодировке.

обычно это как-раз и делается через strlen(str)*sizeof(str[0])

wcstombs. Вообще рекомендую посмотреть всё семейство функций для работы с многобайтом и мультибайтом.

Но у него есть фатальный недостаток — он зависит от текущей локали. Если тебе надо для Unicode, то можно сделать свою функцию.

наверное, как тут уже написали, но на крайняк можно и самому функцию запилить

Но у него есть фатальный недостаток — он зависит от текущей локали. Если тебе надо для Unicode, то можно сделать свою функцию.

Если перевести на русский, что ТС хочет, вполне может оказаться, что хочет он перевести wchar_t * в utf-8 char *, а это от локали не зависит.

В wchar_t необязательно может быть юникод(он может быть даже любого размера, от 8 до 32 байт), да и локалью тоже не обязательно может быть UTF-8.

В wchar_t необязательно может быть юникод

А что там может быть по вашему? Да даже так: а для чего по вашему придуман wchar_t?

да и локалью тоже не обязательно может быть UTF-8.

Безусловно. Но вы читали на что отвечаете? Вообще-то я написал, что ТС скорее всего мог иметь в виду именно это.

А что там может быть по вашему? Да даже так: а для чего по вашему придуман wchar_t?

Там может быть всё что угодно. Хоть клингонский имперский иероглифический скрипт. Стантарт любимой всеми Сишки не определяет ни кодировку, ни размер, ни внутреннее представление? ни кодовую таблицу wchar_t.

Там может быть всё что угодно. Хоть клингонский имперский иероглифический скрипт.

Вот именно. Там могут содержаться символы непредставимые в текущей локали. Но при изменении локали там ничего не меняется. Но собственно : а слабо вникнуть о чём был риторический вопрос? Какое дело как там внутри представлено? По теме есть что сказать? А, ну это же dzidzitop.

ответ от dzidzitop:

Ещё вопросы? Или будет какая-то лекция от «практиков» (слесарей 6 разряда) о том, что только юникод там может быть ибо нефиг?

Я wchar_t избегаю и другим советую. Это говно использовать без сеансов любви с переключением глобальной для всей программы локали невозможно.

У тебя уже развился такой чудовищный комплекс по отношению к C, что тебе впору начинать писать книгу «Как перестать беспокоиться о языке программирования, который ты не используешь и начать жить».

Я его использую в виде фундамента из трёх слонов и черепахи, на котором построен C++.

Расскажи лучше как нужно работать с переменными типа wchar_t. Например, мне нужно сделать функцию

, в которой нужно апперкейснуть строчные буквы украинского алфавита.

Как должен выглядеть правильный и переносимый код этой функции на самом современном C11?

Я не увидел, каким образом можно хоть как-то работать с wchar_t и фактически вычеркнул его из списка средств языка C, с которыми имеет практический смысл связываться.

Насущная задача номер 2: прочитать файл с известной кодировкой (не обязательно системная, но она известна заранее) в строку wchar_t *.

Каким образом это можно сделать переносимо на C11?

обычно это как-раз и делается через strlen(str)*sizeof(str[0])

Тещемта sizeof(str[0]) == 1.

wcstombs() с NULL в первом параметре вернёт длину в мультибайтной кодировке.

Самое то что нужно, большое спасибо, и всем кто поучаствовал.

Расскажи лучше как нужно работать с переменными типа wchar_t. Например, мне нужно сделать функцию

, в которой нужно апперкейснуть строчные буквы украинского алфавита.

А зачем ограничиваться только одним языком?

в разных языках результат toupper отличается. Например в турецком i в upper-case это совсем даже не I.

И этот towupper() не решает задачу классификации букв украинского алфавита. Он работает сразу со всем и ни с чем конкретно.

А уж сконвертировать в wchar_t * текст не в кодировке системной локали вообще хрен пойми как. Вероятно — никак.

в разных языках результат toupper отличается. Например в турецком i в upper-case это совсем даже не I.

utf-8 это как-то решает?

И этот towupper() не решает задачу классификации букв украинского алфавита. Он работает сразу со всем и ни с чем конкретно.

Тогда самостоятельно составлять таблицу соответствия нужных букв по чистому юникоду, как раз UCS-4 прямое его воплощение. utf-8 тут не помощник.

А уж сконвертировать в wchar_t * текст не в кодировке системной локали вообще хрен пойми как. Вероятно — никак.

UTF-8 определяет кодовую таблицу, в которой каждый кодпойнт имент своё чёткое значение, которое может быть правильно интерпретировано. wchar_t никакую кодовую таблицу не определяет. Поэтому с отдельными значениями wchar_t работать семантически не представляется возможным вообще никак.

1) wchar_t != unicode.

2) iconv — рабочий вариант, но к wchar_t от не относится вообще никак. Там даже в API wchar_t отсутствует.

iconv (gnu версия) и костылями с безопасным конвертированием в случае однобайтной системной кодировки и живу.

А что там может быть по вашему? Да даже так: а для чего по вашему придуман wchar_t?

другие многобайтные кодировки

нужно использовать стороннюю библиотеку для этого

UTF-8 определяет кодовую таблицу, в которой каждый кодпойнт имент своё чёткое значение, которое может быть правильно интерпретировано. wchar_t никакую кодовую таблицу не определяет. Поэтому с отдельными значениями wchar_t работать семантически не представляется возможным вообще никак.

Ничего не путаешь, может быть наоборот?

wchar_t это тип из которого кодпойнт извлекается с наименьшими усилиями, раз уж на то пошло.

iconv — рабочий вариант, но к wchar_t от не относится вообще никак. Там даже в API wchar_t отсутствует.

Ну вот же, по русски пишут:

Although inbuf and outbuf are typed as char **, this does not mean that the objects they point can be interpreted as C strings or as arrays of characters: the interpretation of character byte sequences is handled internally by the conversion functions.

Если бы в интерфейсе функции был void** то ты сказал бы что к char никак не относится?

Unicode — определяет кодовую таблицу.

wchar_t — Integral type whose range of values can represent distinct wide-character codes for all members of the largest character set specified among the locales supported by the compilation environment: the null character has the code value 0 and each member of the Portable Character Set has a code value equal to its value when used as the lone character in an integer character constant.

Где тут юникод? Где определение, что, например ((wchar_t) 100500) означает руну «ветер» в системе письменности туземцев Тасмании? Наоборот, говорится, что нихрена тут не определяется.

Для кажного из кодпойнта в юникоде такое описание есть.

И посмотри на и насладись «богатством» возможностей: https://ru.wikipedia.org/wiki/Wchar.h

Но некоторые люди из комитета уже допёрли, что это говно полное, поэтому в C11 появились типы char16_t, char32_t. Но, правда, никаких инструментов работы с ними (хотя бы printf, scanf) не подвезли. Зато каждое значение этих типов однозначно интерпретируется согласно кодовой таблице Unicode.

iconv сделан нормально. С wchar_t он не работает. Он работает с ***конкретными кодировками*** в бинарном формате (т.е. с последовательностью байт).

Хотя, через две(!) конверсии можно из wchar_t получить char32_t: wchar_t * -> wctomb (1) -> mbrtoc32 (2) -> char32_t *

Поддержка Юникода и многобайтовой кодировки Unicode and Multibyte Character Set (MBCS) Support

Некоторые языки, например японский и китайский, имеют большие наборы символов. Some languages, for example, Japanese and Chinese, have large character sets. Для поддержки программирования этих рынков библиотека Microsoft Foundation Class (MFC) предоставляет два разных подхода к обработке больших наборов символов: To support programming for these markets, the Microsoft Foundation Class Library (MFC) enables two different approaches to handling large character sets:

Юникод, wchar_t основанные на расширенных символах и строки в кодировке UTF-16. Unicode, wchar_t based wide-characters and strings encoded as UTF-16.

Многобайтовые кодировки (MBCS) , основанные на символах одиночные или двухбайтовые символы и строки, закодированные в кодировке, зависящей от языкового стандарта. Multibyte Character Sets (MBCS), char based single or double-byte characters and strings encoded in a locale-specific character set.

Корпорация Майкрософт рекомендует использовать библиотеки Юникода MFC для всех новых сред разработки, а библиотеки MBCS не рекомендуются в Visual Studio 2013 и Visual Studio 2015. Microsoft has recommended the MFC Unicode libraries for all new development, and the MBCS libraries were deprecated in Visual Studio 2013 and Visual Studio 2015. Этот режим больше не используется. This is no longer the case. Предупреждения об устаревании многобайтовых кодировок были удалены в Visual Studio 2020. The MBCS deprecation warnings have been removed in Visual Studio 2020.

Поддержка MFC для строк в Юникоде MFC Support for Unicode Strings

Все библиотеки классов MFC условно поддерживаются для символов Юникода, а строки, хранящиеся в расширенных символах, — в кодировке UTF-16. The entire MFC class library is conditionally enabled for Unicode characters and strings stored in wide characters as UTF-16. В частности, класс CString поддерживает Юникод. In particular, class CString is Unicode-enabled.

Эти файлы библиотеки, отладчика и библиотеки DLL используются для поддержки Юникода в MFC: These library, debugger, and DLL files are used to support Unicode in MFC:

УАФКСКВ. LIB UAFXCW.LIB УАФКСКВ. ФАЙЛЕ UAFXCW.PDB УАФКСКВД. LIB UAFXCWD.LIB УАФКСКВД. ФАЙЛЕ UAFXCWD.PDB
Библиотека MFCверсииU. lib MFCversionU.LIB ВерсияU. pdb для MFC MFCversionU.PDB Библиотека MFCверсииU. dll MFCversionU.DLL MFCверсииобновления. LIB MFCversionUD.LIB
MFCверсииобновления. ФАЙЛЕ MFCversionUD.PDB MFCверсииобновления. КОМПОНОВКИ MFCversionUD.DLL МФКСверсияU. lib MFCSversionU.LIB МФКСверсияU. pdb MFCSversionU.PDB
МФКСверсияобновления. LIB MFCSversionUD.LIB МФКСверсияобновления. ФАЙЛЕ MFCSversionUD.PDB МФКМверсияU. lib MFCMversionU.LIB МФКМверсияU. pdb MFCMversionU.PDB
МФКМверсияU. dll MFCMversionU.DLL МФКМверсияобновления. LIB MFCMversionUD.LIB МФКМверсияобновления. ФАЙЛЕ MFCMversionUD.PDB МФКМверсияобновления. КОМПОНОВКИ MFCMversionUD.DLL

(версия представляет номер версии файла, например, «140» означает версию 14,0.) (version represents the version number of the file; for example, ‘140’ means version 14.0.)

CString основана на типе данных TCHAR. CString is based on the TCHAR data type. Если символ _UNICODE определен для сборки программы, то TCHAR определяется как тип wchar_t , 16-разрядный тип кодировки символов. If the symbol _UNICODE is defined for a build of your program, TCHAR is defined as type wchar_t , a 16-bit character encoding type. В противном случае TCHAR определяется как char, обычная 8-разрядная кодировка символов. Otherwise, TCHAR is defined as char, the normal 8-bit character encoding. Таким образом, в Юникоде CString состоит из 16-разрядных символов. Therefore, under Unicode, a CString is composed of 16-bit characters. Без Юникода оно состоит из символов типа char. Without Unicode, it is composed of characters of type char.

Для завершения программирования в Юникоде приложения необходимо также: To complete Unicode programming of your application, you must also:

Используйте макрос _T, чтобы строковые литералы кода можно было перенести в Юникод. Use the _T macro to conditionally code literal strings to be portable to Unicode.

При передаче строк следует обратить внимание на то, требуется ли для аргументов функции длина в символах или длина в байтах. When you pass strings, pay attention to whether function arguments require a length in characters or a length in bytes. Разница важна при использовании строк Юникода. The difference is important if you are using Unicode strings.

Используйте переносимые версии функций обработки строк времени выполнения языка C. Use portable versions of the C run-time string-handling functions.

Используйте следующие типы данных для символов и указателей символов: Use the following data types for characters and character pointers:

Используйте TCHAR, где используется тип char. Use TCHAR where you would use char.

Используйте LPTSTR, где следует использовать char*. Use LPTSTR where you would use char*.

Используйте LPCTSTR, где следует использовать const char*. Use LPCTSTR where you would use const char*. CString предоставляет оператор LPCTSTR для преобразования между CString и LPCTSTR. CString provides the operator LPCTSTR to convert between CString and LPCTSTR.

CString также предоставляет конструкторы, поддерживающие Юникод, операторы присваивания и операторы сравнения. CString also supplies Unicode-aware constructors, assignment operators, and comparison operators.

Ссылка на библиотеку времени выполнения определяет переносимые версии всех функций обработки строк. The Run-Time Library Reference defines portable versions of all its string-handling functions. Дополнительные сведения см. в разделе Международная связькатегории. For more information, see the category Internationalization.

Поддержка MFC для строк MBCS MFC Support for MBCS Strings

Библиотека классов также включена для многобайтовых кодировок, но только для двухбайтовых наборов символов (DBCS). The class library is also enabled for multibyte character sets, but only for double-byte character sets (DBCS).

В многобайтовой кодировке символ может иметь один или два байта в ширину. In a multibyte character set, a character can be one or two bytes wide. Если для него задано значение в два байта, его первый байт — это специальный «старший байт», который выбирается из определенного диапазона в зависимости от используемой кодовой страницы. If it is two bytes wide, its first byte is a special «lead byte» that is chosen from a particular range, depending on which code page is in use. Вместе, ведущий и «младший байт» задают уникальную кодировку символов. Taken together, the lead and «trail bytes» specify a unique character encoding.

Если символ _MBCS определен для сборки программы, то тип TCHAR, на котором CString основана, сопоставляется с char. If the symbol _MBCS is defined for a build of your program, type TCHAR, on which CString is based, maps to char. Вы должны определить, какие байты a CString являются старшими байтами, а какие — конечными байтами. It is up to you to determine which bytes in a CString are lead bytes and which are trail bytes. Библиотека времени выполнения языка C предоставляет функции, помогающие определить это. The C run-time library supplies functions to help you determine this.

В двухбайтовой кодировке DBCS заданная строка может содержать все однобайтовые ANSI-символы, все двухбайтовые символы или сочетание двух. Under DBCS, a given string can contain all single-byte ANSI characters, all double-byte characters, or a combination of the two. Для этих возможностей требуется особая осторожность при анализе строк. These possibilities require special care in parsing strings. Сюда входят CString объекты. This includes CString objects.

Сериализация строк Юникода в MFC может считывать строки как в Юникоде, так и в многобайтовой кодировке независимо от того, какая версия приложения используется. Unicode string serialization in MFC can read both Unicode and MBCS strings regardless of which version of the application that you are running. Файлы данных переносимы между Юникодом и многобайтовой версией программы. Your data files are portable between Unicode and MBCS versions of your program.

CString функции-члены используют специальные «универсальные» версии функций среды выполнения C, которые они вызывают, или используют функции, поддерживающие Юникод. CString member functions use special «generic text» versions of the C run-time functions they call, or they use Unicode-aware functions. Поэтому, например, если CString функция strcmp обычно вызывает, вместо этого вызывается соответствующая универсальная функция _tcscmp . Therefore, for example, if a CString function would typically call strcmp , it calls the corresponding generic-text function _tcscmp instead. В зависимости от того, как определяются символы _MBCS и _UNICODE _tcscmp , сопоставляет их следующим образом: Depending on how the symbols _MBCS and _UNICODE are defined, _tcscmp maps as follows:

_MBCS определено _MBCS defined _mbscmp
_UNICODE определено _UNICODE defined wcscmp
Не определен ни один символ Neither symbol defined strcmp

Символы _MBCS и _UNICODE являются взаимоисключающими. The symbols _MBCS and _UNICODE are mutually exclusive.

Сопоставления универсальных текстовых функций для всех подпрограмм обработки строк во время выполнения обсуждаются в справочнике по библиотеке времени выполнения C. Generic-text function mappings for all of the run-time string-handling routines are discussed in C Run-Time Library Reference. Список см. в разделе интернационализации. For a list, see Internationalization.

Аналогичным CString образом, методы реализуются с помощью универсальных сопоставлений типов данных. Similarly, CString methods are implemented by using generic data type mappings. Чтобы включить многобайтовую кодировку и Юникод, MFC использует TCHAR wchar_t для char или, LPTSTR wchar_t* для char * или и LPCTSTR для const char * или const wchar_t* . To enable both MBCS and Unicode, MFC uses TCHAR for char or wchar_t , LPTSTR for char* or wchar_t* , and LPCTSTR for const char* or const wchar_t* . Они обеспечивают правильное сопоставление для MBCS или Юникода. These ensure the correct mappings for either MBCS or Unicode.

Многобайтные символы (mutibyte chars).

Введение

Для того, чтобы понять, что такое «многобайтные символы» необходимо прежде всего определиться с термином «байт«.

Принято считать, что байт — это порция информации, состоящая из восьми бит. Но существует и намного более точное определение — октет . То есть, в принципе, мы можем группировать информацию порциями любого другого размера. Например, в телеграфии до сих пор применяются пяти -битные порции информации (байты).

Максимальное количество разных значений, которые мы можем закодировать в восьми-битном байте — 256=2 8 (от 0 до 255) а в пяти-битном — 32=2 5 .

Теперь предположим, что нам необходимо закодировать некую информацию, например символы алфавита (буквы) в двоичных числах. Подробно об операциях кодирования см. Языки, символы и кодировки.

Рассмотрим, например, тот же телеграфный код. Оказывается, закодировать 26 английских букв и 10 цифр в 32 разные комбинации не удается. Для этого применяют специальный символ : переключение регистра . А если сюда добавить еще и русские буквы, регистров становится целых три : ЛАТ, РУС, ЦИФ. Именно так образуется Международный Телеграфный трех-регистровый Код MTK-2, принятый в CCCP в 1963 году.

Если кто-нибудь еще помнит такую технику, как ДВК (Диалоговый Вычислительный Комплекс), то там применялся КОИ-7 (Код Обмена Информацией, 7-ми битный). Однако этот код содержал все символы ASCII, (маленькие и большие латинские буквы) и все символы кириллицы, также маленькие и большие. Что в результате давало более чем 128=2 7 кодовых позиций. А для переключения между латинской КОИ-7Н0 (набор N0) и русской КОИ7-Н1 (набор N1) половинами использовались коды SO (Shift Out, 014) и SI (Shift In, 015).

Например для того, чтобы отобразить на терминале фразу : «Мир, Peace» необходимо послать следующие символы :

SO 0155 0111 0122 054 040 SI 0120 0145 0141 0143 0145

После переключения в другую кодовую страницу (русский регистр) его состояние сохраняется до переключения в латинский регистр.

Таким образом мы приходим к важнейшему понятию в технологии многобайтных символов : Shift State (можно перевести как Регистр или Состояние Регистра). На самом деле, таких состояний (регистров) может быть несколько, они могут быть взаимоисключающими, или же действовать одновременно и независимо.

Отсюда несколько важных выводов : при обработке многобайтовых символов необходимо сохранять текущее состояние Shift State. Длина байтовой последовательности более не соответствует количеству печатных символов в строке. То есть, взяв символ по смещению НАЧАЛО+8 мы не можем достоверно сказать, что это именно 8-й отображаемый символ. Точно также, мы не можем сказать, в каком кодовом наборе необходимо будет отобразить этот символ. То есть, строка имеет историю. И получить полную информацию мы можем только просмотрев строку с начала (считается, что имеется некое «начальное состояние» регистров).

Другая проблема связана со свойством «длина строки». Для строк, состоящих из многобайтовых символов, длина строки «в символах» не равна длине строки «в байтах». Например функция strlen() может работать некорректно. Поэтому, многие системы с поддержкой многобайтовых символов часто имеют две различных функции, например : char_len() и octet_len().

Схемы.

Существует несколько схем организации (кодирования) многобайтовых последовательностей. Самые распространенные :

  • ISO-2022
  • UTF-8

Менее распространенные : EUC, Shift-JIS (DBCS). С некоторой натяжкой к Multibyte можно отнести UUENCODE, BASE-64 (вместе с QP) и NCR.

ISO-2022

Самое большое влияние на Multibyte chars оказал стандарт ISO-2022. Его текст к сожалению доступен только за деньги, но существует его полный бесплатный аналог ECMA-35.

Согласно стандарту ISO-2022 вводится понятия «управляющий символ» и «графический символ», напрмер C R , LF или ESC — это управляющие символы. Соответственно, все пространство из 2 8 =256 символов разбивается на четыре части :

  • C0 (Control Left) — 0x00-0x1F
  • GL (Graphic Left) — 0x20-0x7F
  • C1 (Control Rigth) — 0x80-0x9F
  • GR (Graphic Right) — 0xA0-0xFF

Таким образом под «отображаемые» символы (Graphic) отводится только 256-2*32=192 позиции, 96 GL и 96 GR (иногда 94, без первой и последней позиций).

Одной из функций «управляющих» символов является переключение наборов символов в GR и GL. То есть, вся «пляска» происходит внутри 8-ми битного пространства. Для этого применяется управляющие ESC-последовательности, «старший» ESCCSI и коды SI и SO . Например, уже упоминавшийся КОИ-7 сделан в точном соответствии со стандартом ISO-2022, путем переключения GL кодами SI и SO (Удивительно ?).

Например, большинство принтеров используют для переключения кодовых наборов именно различные ESC-последовательности. И при вывод на печать постоянно происходит переключение » наборов символов » с помощью управляющих кодов. Точно такая же картина с терминалами. Например терминалы DEC VT-XXX или Wyse имеют множество национальных наборов символов, вшитых в микрокод. Даже код переключения кодовых наборов у консоли Linux (echo -ne «\033(K» ) — это тоже разновидность последовательности ISO-2022. ( см. man console_codes )

Каждой половине, GR и GL, может быть назначен определенный набор символов (Charset). Существуют четыре набора графических символов G0/G1/G2/G3, каждый из которых может быть подключен на место GL или GR. Как правило, в 8-ми битных системах для GL назначается обычный ASCII, а GR переключают.

Вдобавок, каждый из Charset-ов G0/G1/G2/G3 тоже можно сменить с помощью «назначателей» (designators). Получается довольно сложная и громоздкая система. А все из-за 8-ми битного байта !

См. ECMA-35 — полный аналог ISO-2022 (бесплатно).

При чтении стандарта ISO-2022 и ECMA-35 может ввести в смущение необычная схема нумерации кодовых позиций, например 2/5. На самом деле, это номер колонки (0..15) и номер символа в колонке (0..15). То есть фактически это шестнадцатеричные числа ! Упомянутое выше число 2/5 означает шестнадцатеричное 0x25 (3710). Символ ESC — это 01/11 == 0x1B == 2710.

Международные стандарты серии ISO-8859-x ( например ISO-8859-1 : Latin1) сконструированы с учетом требований ISO-2022 . «Назначатели» для них также стандартизованы. Например для кодировки ISO-8859-5 «назначателями» будут : G1 — ESC 2/13 4/12; G2 — ESC 2/14 4/12; G3 — ESC 2/15 4/12.

Одним из недостатков ISO-2022 является запрет на использование позиций «старших» управляющих символов C1 (0x80-0x9F) для кодирования букв. Например, кодировка CP-866 не соответствует стандарту ISO-2022, поскольку код буквы «Ы» (0x9B) совпадает со старшим ESC (CSI).

Кодировка ISO-2022 является «внутренней» кодировкой для Emacs.

Кодировки на основе ISO-2022 практически в «чистом виде», то есть вместе с ESC-символами и «назначателями» широко применяется для кодирования японских символов (система JIS) и имеют зарегистрированные MIME charset-ы: ISO-2022-JP (RFC-1468) и ISO-2022-JP-1 (RFC-2237).

CTEXT

Система X Window проектировалась в 1970-х годах и в качестве «внутренней» кодировки международных символов в ней была применена схема CTEXT (Compound Text Encoding ). Эта кодировка используется вне зависимости от кодировки «целевой» операционной системы (Unix, Windows). Поскольку X — сетевой протокол, то кодировки клиента (множества клиентов) и X-сервера могут различаться.

В кодировке CTEXT могут сохраняться свойств окон X (window propirties) и «ресурсов» внутри X сервера. Эти же «ресурсы» используются для межпрограммного общения через ICСCM и для общения X-программы с WindowManager-ом.

Эта схема кодирования идеологически довольно близка к ISO-2022, но поддержка управляющих символов сильно упрощена и «назначатели» в ней часто применяются другие (хотя для упоминавшейся выше ISO8859-5 — тот же самый: 4/12 ). Кроме того, схема CTEXT более гибка и позволяет добавлять новые кодировки (например Windows-1251) как «other ecoding» — то есть просто по имени.

Стандарт на кодировку CTEXT свободен и имеется в комплекте документации на систему X ( например XFree) или тут.

Для преобразования строк в » свойства » существуют функции XmbTextListToTextProperty() / XwcTextListToTextProperty() и обратные XmbTextPropertyToTextList() / XwcTextPropertyToTextList () где для кодирования в COMPOUND_TEXT может использоваться XCompoundTextStyle.

В результате мы получаем Си-строку, в которой коды символов перемежаются кодами «переключения кодировки». Соответствие между «назначателями» CTEXT и названием кодировки (напр. *-iso8859-1) могут использоваться для выбора шрифта XLFD (X Logical Font Description) для отрисовки данной строки символов в окне, заголовке окна X или подписи под иконкой в Window Manager-е.

  • CTEXT (Compound Text) HTML
  • ICСCM (Inter-Client Communication Conventions Manual)
  • XLFD (X Logical Font Description) HTML
  • Juliusz Chroboczek, Fonts in XFree86

Самые последние версии спецификации CTEXT (>1.1) имеют расширение для интеграции с кодировкой UTF-8 ( имеют стандартизованный » назначатель » для UTF-8).

UTF-8 применяет совершенно другую схему образования многобайтных кодов.

Изначально символы из набора UNICODE и ISO-10646 закодированы не байтами (8 бит), а 16— или 32-битными числами ( wc — wide characters ). Для кодирования 32-битного числа ISO10646 применяется следующая схема (RFC-2279)

U-00000000 — U-0000007F: xxxxxxx
U-00000080 — U-000007FF: 110xxxxx 10xxxxxx
U-00000800 — U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 — U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 — U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 — U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

Таки образом, 7-ми битные US-ASCII символы остаются неизменными, а все остальные символы кодируются переменным количеством байт. Максимальное число байт для UTF-8 составляет 6. Символы кириллицы кодируются двумя байтами.

В файле (потоке) UTF-8 никогда не бывает нулевых байтов и управляющих последовательностей (ESC).

Преимущество кодировки UFT-8 в том, что она является само-синхронизирующейся . То есть при потере одного-двух байт, следующий закодированный символ может быть восстановлен. Это выгодно отличает ее от ISO-2022, в которой стоки имеют state (состояние) и при потере «назначателей» (designators) мы теряем сведения о кодировке.

JVM (Java Virtual Machine) использует кодировку UTF-8 в качестве «внутренней» для хранения строк и включает перекодировку при записи строк в поток «наружу», в файлы и потоки целевой ОС.

Как работать с многобайтными символами ? (API)

В стандарт POSIX включено целое семейство функций для работы с многобайтными символами. mb* в том числе и для преобразования многобайтных символов в «широкие» wc*

Стандартные функции для работы с битами и байтами на Arduino

Описание стандартных функция для работы с битами (получение значения, очистка, установка, запись) и байтами (извлечение старшего и младшего байтов) на Arduino.

Содержание

Описание функций

Вычисляет значение указанного бита (бит 0 равен 1, бит 1 равен 2, бит 2 равен 4, и так далее).

Синтаксис

Параметры

n : бит, значение которого необходимо вычислить.

Возвращает

Очищает (записывает 0) бит числовой переменной.

Синтаксис

Параметры

x : числовая переменная, в которой необходимо очистить бит.

n : какой бит необходимо очистить, счет начинается с 0 для самого младшего значащего (самого правого) бита.

Возвращает

Прочитать бит числа.

Синтаксис

Параметры

x : число, в которого необходимо прочитать.

n : какой бит необходимо прочитать, счет начинается с 0 для самого младшего значащего (самого правого) бита.

Возвращает

Значение бита (0 или 1).

Установить (записать 1) бит числовой переменной.

Синтаксис

Параметры

x : числовая переменная, в которой необходимо установить бит.

n : какой бит необходимо установить, счет начинается с 0 для самого младшего значащего (самого правого) бита.

Возвращает

Запсать бит числовой переменной

Синтаксис

Параметры

x : числовая переменная, в которой необходимо записать бит.

n : какой бит необходимо записать, счет начинается с 0 для самого младшего значащего (самого правого) бита.

b : значение, которое необходимо записать в бит (0 или 1).

Возвращает

Извлекает старший по порядку (самый левый) байт из слова word (или второй самый младший байт из большего типа данных).

Синтаксис

Параметры

x : значение любого типа.

Возвращает

Извлекает младший по порядку (самый правый) байт из переменной (например, типа word ).

Программирование: Разработка и отладка программ

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

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

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

Внимание : Преобразование между многобайтовым кодом и кодом широких символов определяется текущей локалью. Нельзя выполнять обмен широкими символами между двумя процессами, если вы не уверены, что каждая из используемых локалей правильно интерпретирует их. Большинство локалей AIX воспринимают символы Unicode как широкие символы, за исключением локалей, основанных на кодовых наборах IBM-850 и IBM-eucTW.

При преобразовании многобайтовых символов в широкие символы применяются следующие функции:

mblen

Вычисляет длину многобайтового символа.
mbstowcs

Преобразует строку многобайтовых символов в строку широких символов.
mbtowc

Преобразует многобайтовый символ в широкий символ.

При преобразовании широких символов в многобайтовые символы применяются следующие функции:

wcslen

Определяет число широких символов в строке.
wcstombs

Преобразует строку широких символов в строку многобайтовых символов.
wctomb

Преобразует широкий символ в многобайтовый символ.


    В следующем примере для преобразования многобайтового символа в широкий применяется функция mbtowc .

В следующем примере для преобразования широкого символа в многобайтовый применяется функция wctomb :

В следующем примере для определения длины многобайтового символа (в байтах) применяется функция mblen :

В следующем примере определяется позиция предыдущего символа в строке многобайтовых символов. Если вам требуется определить позицию предыдущего символа, начиная с позиции текущего символа (а не с некоторой случайной позиции), то вам придется перебрать все символы в буфере, начиная с начала. Вызывайте функцию mblen , пока не достигнете позиции текущего символа, и сохраняйте позицию предыдущего символа.

В следующем примере для преобразования строки многобайтовых символов в строку широких символов применяется функция mbstowcs :

В следующем примере проиллюстрировано преобразование большого блока данных в широкий формат с помощью функции mbstowcs . Когда функция mbstowcs обнаруживает недопустимый многобайтовый символ, она возвращает значение -1 , но не указывает, где произошла ошибка. Поэтому функцию mbtowc следует использовать в цикле, чтобы она преобразовывала по одному символу.

Примечание: Такой способ обработки значительно замедляет выполнение программы.

Примечание: Возвращается строка широких символов, оканчивающаяся символом NULL. При обнаружении недопустимой последовательности байт может быть выполнена дополнительная обработка ошибок.

В следующем примере для преобразования строки широких символов в строку многобайтовых символов применяются функции wcstombs и wcslen :

Большинство функций классификации широких символов аналогичны функциям классификации обычных символов, за исключением того, что первые работают с аргументом типа wchar_t , передаваемым как аргумент типа wint_t .

В среде с поддержкой национальных языков важную роль играет возможность создания новых свойств классов символов. Например, для символов японского языка определены некоторые свойства, не применимые к символам английского языка. По этой причине, для поддержки большого числа языков необходима среда, позволяющая приложениям работать с различными свойствами символов. Для работы с классами символов в общей форме предназначены функции wctype и iswctype . Эти функции позволяют работать как с классами пользовательских символов, так и с классами символов конкретных языков.

Действие функций классификации широких символов зависит от значения категории LC_CTYPE текущей локали.

Для создания нового класса символов, который будет определяться функциями wctype и iswctype , необходимо задать его свойства в категории LC_CTYPE и определить локаль командой localedef . Пользовательское приложение получит данные этой локали с помощью функции setlocale . Затем программа сможет получить доступ к новым функциям классификации, используя при этом функцию wctype для получения описателя свойства wctype_t . После этого описатель свойства и код проверяемого широкого символа можно будет передать функции iswctype .

Получает описатель для классификации свойства символа. iswctype

Проверяет свойство символа.

Функции isw* позволяют определить разнообразные аспекты стандартной классификации широких символов. Кроме того, функции isw* поддерживают наборы однобайтовых символов. Если это возможно, следует применять функции isw* вместо функций wctype и iswctype . Функции wctype и iswctype следует использовать только для работы с дополнительными свойствами классов символов (например, со свойствами японского языка).

Если функции обработки широких символов применяются для преобразования регистра в нескольких блоках данных, то приложение должно преобразовывать многобайтовые символы в широкие символы. Поскольку это может повлиять на быстродействие программы в случае локалей с однобайтовыми кодовыми наборами, в приложение необходимо предусмотреть два способа изменения регистра. Традиционный способ, применяемый для локалей с однобайтовыми кодовыми наборами, — это использование функций isupper , islower , toupper и tolower . Альтернативный способ, применяемый в локалях с многобайтовыми кодовыми наборами, заключается в том, что сначала выполняется преобразование многобайтовых символов в широкие, а затем с помощью функций iswupper , iswlower , towupper и towlower изменяется регистр. При преобразовании многобайтовых символов в широкие приложению придется обрабатывать некоторые специальные случаи, когда многобайтовый символ занимает несколько последовательных блоков.

Проверяет, является ли символ алфавитно-цифровым. iswalpha

Проверяет, является ли символ алфавитным. iswcntrl

Проверяет, является ли символ управляющим. iswdigit

Проверяет, является ли символ цифрой. iswgraph

Проверяет, является ли символ графическим. iswlower

Проверяет, относится ли символ к нижнему регистру. iswprint

Проверяет, является ли символ печатаемым. iswpunct

Проверяет, является ли символ знаком пунктуации. iswspace

Определяет, является ли символ пробелом. iswupper

Проверяет, относится ли символ к верхнему регистру. iswxdigit

Проверяет, является ли символ шестнадцатеричным числом.

Ниже перечислены функции, изменяющие регистр широких символов. Выполняемые ими действия зависят от определений, заданных в категории LC_CTYPE для текущей локали.

towlower

Преобразует широкий символ верхнего регистра в широкий символ нижнего регистра.
towupper

Преобразует широкий символ нижнего регистра в широкий символ верхнего регистра.

В следующем примере функция wctype используется для проверки принадлежности символов классу NEW_CLASS :

При выводе символов на экран или принтер число столбцов, занимаемых каждым символом, может быть различным. Например, символ канжи (японский иероглиф) может занимать несколько столбцов. Число столбцов экрана, требуемое для отображения каждого символа, задано в базе данных локали Поддержки национальных языков (NLS), в категории LC_CTYPE .

Стандартных функций для определения ширины многобайтового символа не существует. Для обеспечения переносимости приложений необходимо преобразовать многобайтовые символы в широкие и использовать функции определения ширины широких символов. Однако если в файле stdlib.h задано макроопределение, присваивающее переменной __max_disp_width значение 1, и используется кодовый набор однобайтовых символов, то все символы данного кодового набора (кроме символов табуляции) занимают по одному столбцу на экране. В этом случае число столбцов, занимаемое строкой на экране (ширина строки), определяется с помощью функции strlen ( строка ) . Это проиллюстрировано в следующем примере:

Для определения числа столбцов, занимаемых строкой широких символов на экране, предназначены следующие функции:

wcswidth

Определяет длину строки широких символов на экране.
wcwidth

Определяет ширину широкого символа на экране.

  1. В этом примере с помощью функции wcwidth определяется ширина широкого символа на экране:

В этом примере с помощью функции wcswidth определяется длина строки широких символов на экране:

Сравнение строк может выполняться двумя способами:

  • На основании порядковых (двоичных) значений символов.
  • На основании весов символов, заданных в каждой локали в категории LC_COLLATE category.

В NLS (Поддержке национальных языков) применяется второй способ.

Упорядоченность — это свойство символов, определяемое локалью. Каждому символу ставится в соответствие вес, соответствующий его относительному положению в последовательности сортировки. Символу может соответствовать несколько весов, распределяемых по приоритету: основной, дополнительный, третьего уровня и т.д. Максимальное число весов, которое может быть присвоено одному символу, определяется системой.

Во время запуска процесса он наследует локаль C или локаль POSIX. При вызове функции setlocale (LC_ALL, » «) локаль, получаемая процессом, определяется переменными среды LC_* и LANG . Порядок сортировки двух строк в данной локали определяется перечисленными ниже функциями, действия которых зависят от значения категории LC_COLLATE .

Примечание: Сравнение строк на основе весов символов занимает значительное время, так как требуется запрашивать веса. Такие операции сравнения должны выполняться только в случае крайней необходимости. Если вам нужно сравнить две строки, состоящие из широких символов, не применяйте для этого функции wcscoll и wcsxfrm . Лучше воспользуйтесь функцией wcscmp .

Для весового сравнения строк многобайтовых символов предназначены следующие функции:

strcoll

Сравнивает строки многобайтовых символов на основе весов символов.
strxfrm

Преобразует строку многобайтовых символов в значения весов символов.

Для весового сравнения строк широких символов предназначены следующие функции:

wcscoll

Сравнивает строки широких символов на основе весов символов.
wcsxfrm

Преобразует строку широких символов в значения весов символов.

  1. В следующем примере для весового сравнения двух строк широких символов применяется функция wcscoll :

В следующем примере для сравнения двух строк широких символов на основе весов символов применяется функция wcsxfrm :

Примечание: Определить длину n преобразованной строки ( n — число) при работе с функцией wcsxfrm можно одним из следующих способов:

  1. Для любого символа из строки широких символов число байт возможных весов не может превышать COLL_WEIGHTS_MAX * sizeof(wchar_t) . Это значение, умноженное на число широких символов, дает необходимый размер буфера. К размеру буфера прибавьте 1 для учета завершающего символа NULL. Применение этого способа сильно замедляет выполнение программы.
  2. Оцените возможную длину строки в байтах. Если полученная ранее величина недостаточна, увеличьте ее. При этом способе, скорее всего, будут учтены не все строки, зато быстродействие будет максимальным.
  3. Вызовите функцию wcsxfrm дважды: первый раз для вычисления значения n , а второй — для преобразования строки с использованием найденного значения n . Повторный вызов функции wcsxfrm замедлит выполнение программы, зато позволит найти точный размер буфера, предназначенного для хранения преобразованной строки.

Выбор способа зависит от характеристик строк и от требований к производительности программы.

Функции strcmp и strncmp определяют, одинаково ли содержимое двух строк многобайтовых символов. Если приложению необходима информация о лексических различиях между строками, воспользуйтесь функциями весового сравнения строк многобайтовых и широких символов.

Для порядкового сравнения строк широких символов предназначены следующие функции NLS:

wcscmp

Сравнивает две строки широких символов.
wcsncmp

Сравнивает указанное число строк широких символов.

В следующем примере для сравнения двух строк широких символов используется функция wcscmp :

Для преобразования строк, состоящих из широких символов, в числа двойной точности, а также длинные целые числа со знаком или без знака предназначены следующие функции NLS:

wcstod

Преобразует строку широких символов в вещественное число двойной точности.
wcstol

Преобразует строку широких символов в длинное целое число со знаком.
wcstoul

Преобразует строку широких символов в длинное целое число без знака.

Перед вызовом функции wcstod , wcstoul или wcstol необходимо присвоить глобальной переменной errno значение 0 — это позволит правильно обрабатывать все ошибки, возникающие при обращении к этим функциям.

  1. В следующем примере для преобразования строки широких символов в вещественное число двойной точности применяется функция wcstod :

В следующем примере для преобразования строки широких символов в длинное целое число со знаком применяется функция wcstol :

В следующем примере для преобразования строки широких символов в длинное целое число без знака применяется функция wcstoul :

Для копирования строк широких символов предназначены следующие функции NLS:

wcscpy

Копирует строку широких символов в другую строку широких символов.
wcsncpy

Копирует указанное число символов из одной строки широких символов в другую строку широких символов.
wcscat

Добавляет одну строку широких символов к другой строке широких символов.
wcsncat

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

В следующем примере для копирования строки широких символов в массив широких символов применяется функция wcscpy :

Для выполнения поиска в строках широких символов предназначены следующие функции NLS:

wcschr

Ищет первое вхождение широкого символа в строку широких символов.
wcsrchr

Ищет последнее вхождение широкого символа в строку широких символов.
wcspbrk

Ищет первое вхождение нескольких широких символов в строку широких символов.
wcsspn

Определяет число широких символов в начальном сегменте строки широких символов.
wcscspn

Ищет строку широких символов.
wcswcs

Ищет первое вхождение строки широких символов в другую строку широких символов.
wcstok

Разбивает строку широких символов на отдельные подстроки.

  1. В следующем примере для поиска первого вхождения широкого символа в строку широких символов применяется функция wcschr :

В следующем примере для поиска последнего вхождения широкого символа в строку широких символов применяется функция wcsrchr :

В следующем примере для поиска первого вхождения нескольких широких символов в строку широких символов применяется функция wcspbrk :

В следующем примере для определения числа широких символов в начальном сегменте строки широких символов применяется функция wcsspn :

В следующем примере для определения числа широких символов, не входящих в сегмент строки широких символов, применяется функция wcscspn :

В следующем примере для определения первого вхождения строки широких символов в другую строку широких символов применяется функция wcswcs :

В следующем примере с помощью функции wcstok выполняется разметка строки широких символов:

В NLS поддерживаются функции как форматированного, так и неформатированного ввода-вывода.

К семейству функций printf и scanf добавлены функции, позволяющие форматировать широкие символы. Для обработки широких символов в функциях printf и scanf предусмотрены два дополнительных спецификатора формата: %C и %S. Они предназначены для ввода-вывода широкого символа и строки широких символов, соответственно. Эти спецификаторы формата подобны спецификаторам %c и %s, позволяющим выполнять ввод-вывод многобайтовых символов и строк.

Функции обработки многобайтовых символов принимают на входе массив многобайтовых символов и возвращают также массив многобайтовых символов. Для преобразования массива многобайтовых символов, возвращаемого такой функцией, в строку широких символов можно воспользоваться функцией mbstowcs .

Функции неформатированного ввода-вывода применяются в тех случаях, когда ввод-вывод многобайтовых символов в программе не должен зависеть от кодового набора. Например, для ввода многобайтового символа можно использовать функцию fgetwc или getwc . Если программа использует функцию getc для ввода многобайтовых символов, функция getc должна вызываться для ввода каждого байта многобайтового символа.

Функции ввода широких символов извлекают из потока многобайтовые символы и преобразуют их в широкие символы. Преобразование выполняется так же, как при вызове функций mbtowc и mbstowcs .

Функции вывода широких символов преобразуют широкие символы в многобайтовые и помещают результат в поток. Преобразование выполняется так же, как при вызове функций wctomb и wcstombs .

Работа функций ввода-вывода широких символов зависит от значения категории LC_CTYPE текущей локали.

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


    В случае многобайтовых символов для чтения блока текста в буфер следует применять функцию read или fread . Для посимвольного преобразования содержимого буфера применяйте функцию mbtowc . Рассмотрите специальные случаи, когда многобайтовые символы попадают на границы блоков. Функцию mbstowcs для обработки многобайтовых символов в этом буфере применять не следует. Если функция mbstowcs обнаруживает неверный или неполный многобайтовый символ, то она возвращает -1, но не указывает, какая часть данных была преобразована. Функцию mbstowcs можно использовать с однобайтовыми символами, так как в этом случае проблем с неполными последовательностями байт не возникает.

  • Для считывания строки из файла применяйте функцию fgetws . Если полученная строка широких символов содержит символ , то это означает, что получена целая строка. Если широкий символ отсутствует, то строка оказалась длиннее, чем ожидалось, и для считывания всей строки необходимо повторно вызвать функцию fgetws . Если программа может эффективно обрабатывать по одной строке, рекомендуется использовать именно такой подход.
  • Если для построчного считывания файла, состоящего из многобайтовых символов, применяется функция fgets , то существует вероятность неполного считывания многобайтового символа. Функция должна обрабатывать эту ситуацию так же, как функция read . Если вы можете гарантировать, что длина входной строки не превысит установленного предела, то можно использовать буфер соответствующего размера (плюс 1 байт для NULL-символа), избегая, таким образом, разбиения многобайтовых символов. Если программа может эффективно обрабатывать по одной строке, такой подход уместен. Из-за возможного разбиения символов в буфере вместо функции fgets для обработки многобайтовых символов следует использовать функцию fgetws .
  • Для считывания по одному широкому символу можно использовать функцию fgetwc . Однако если файл слишком велик, затраты на вызов этой функции становятся чрезмерными и сводят на нет достоинства данного метода.
  • Какой из этих двух способов использовать, зависит от конкретной программы. Рекомендуется применять второй метод, поскольку он обеспечивает более высокую производительность и программе не нужно обрабатывать специальные случаи.

    Для представления кода широкого символа, а также признака конца файла (EOF) требуется новый тип данных — wint_t . Рассмотрим, например, функцию fgetwc , возвращающую код широкого символа:

    Илон Маск рекомендует:  Что такое код elseif
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL
    wchar_t fgetwc(); Если тип данных wchar_t определен как значение char , то в кодовом наборе ISO8859-1 символ y-умляут неотличим от признака конца файла (EOF), поскольку кодовый знак y-умляута — 0xFF. Следовательно, возвращаемое значение не может быть типом данных wchar_t . Необходим тип данных, в котором могут сохраняться и символы EOF, и все кодовые знаки кодового набора.
    int fgetwc(); На некоторых компьютерах тип данных int определен как 16-разрядный. Если длина типа данных wchar_t больше 16 разрядов, то не все возвращаемые значения могут быть представлены типом int .

    По этим причинам, значение, возвращаемое функцией fgetwc , должно быть представлено типом данных wint_t . Тип данных wint_t определен в файле wchar.h .

    Для ввода широких символов предназначены следующие функции:

    fgetwc Извлекает следующий широкий символ из потока.
    fgetws

    Извлекает строку широких символов из потока.
    getwc Извлекает следующий широкий символ из потока.
    getwchar

    Считывает следующий широкий символ из стандартного файла ввода.
    getws

    Считывает строку широких символов из стандартного файла ввода.
    ungetwc

    Помещает широкий символ в поток.

    Для вывода широких символов предназначены следующие функции:

    fputwc

    Помещает широкий символ в выходной поток.
    fputws

    Помещает строку широких символов в выходной поток.
    putwc

    Помещает широкий символ в выходной поток.
    putwchar

    Отправляет широкий символ в стандартный файл вывода.
    putws

    Отправляет строку широких символов в стандартный файл вывода.

    1. В следующем примере с помощью функции fgetwc выполняется чтение широких символов из файла:

    В следующем примере с помощью функции getwchar выполняется чтение широких символов из стандартного файла ввода:

    В следующем примере с помощью функции ungetwc выполняется занесение широкого символа во входной поток:

    В следующем примере с помощью функции fgetws выполняется построчное чтение файла:

    В следующем примере с помощью функции fputwc выполняется запись широких символов в выходной поток:

    В следующем примере с помощью функции fputws выполняется запись строки широких символов в файл:

    Константа L может применяться только для символов ASCII. Для символов ASCII значение константы L равно кодовому знаку символа. Например, L’a’ — это то же самое, что и a . Константа L применяется в том случае, если необходимо получить значение wchar_t символа ASCII. Спецификатор L задает т.н. константу широких символов. Например:

    Код широкого символа, соответствующий символу x , хранится в wc . Компилятор C преобразует символ x в широкий символ с помощью функции mbtowc или mbstowcs . Это преобразование выполняется в соответствии с параметрами локали, существующими на момент компиляции. Так как символы ASCII входят во все поддерживаемые кодовые наборы и во всех локалях представляются одними и теми же широкими символами, то L’x’ во всех кодовых наборах имеет одно и то же значение. Однако, если x — не ASCII-символ, то программа не будет работать, если запустить ее с иным кодовым набором, нежели тот, что использовался при компиляции. Это ограничение относится к программам, использующим представление константы широких символов в операторах switch.

    См. пример фрагмента программы, откомпилированной с кодовым набором IBM-850.

    Если эта программа компилируется и запускается в системе с кодовым набором IBM-850, она будет работать правильно. Однако, если запустить этот исполняемый файл в системе с кодировкой ISO8859-1, то произойдет сбой. В кодовых наборах IBM-850 и ISO8859-1 коды символов a-умляут и c-седиль различны.

    Раздел Функции для поддержки национальных языков — Обзор — функции обработки широких и многобайтовых символов.

    Описание категории LC_COLLATE файла определения локалей в руководстве AIX 5L Version 5.1 Files Reference .

    Описание категории LC_CTYPE файла определения локалей в руководстве AIX 5L Version 5.1 Files Reference .

    Команда localedef в руководстве AIX 5L Version 5.1 Commands Reference, Volume 3

    Процедуры getc и printf в руководстве AIX 5L Version 5.1 Technical Reference: Base Operating System and Extensions Volume 1 ; процедуры read , scanf , setlocale и strlen в руководстве AIX 5L Version 5.1 Technical Reference: Base Operating System and Extensions Volume 2 .

    Функции мультибайтных строк

    Стандарт Unicode был предложен некоммерческой организацией Unicode Consortium, образованной в 1991 г. Для представления каждого символа в этом стандарте используются два байта, что позволяет закодировать очень большое число символов из разных письменностей: в документах Unicode могут соседствовать русские, латинские, греческие буквы, китайские иероглифы и математические символы. Кодовые страницы становятся ненужными.

    Общие сведения

    Коды в Unicode разделены на несколько областей. Область с кодами от 0000 до 007F содержит символы набора Latin 1 (младшие байты соответствуют кодировке ISO 8859-1). Далее идут области, в которых расположены знаки различных письменностей, а также знаки пунктуации и технические символы; часть кодов зарезервирована для использования в будущем. Символам кириллицы выделены коды в диапазоне от 0400 до 0451.

    Для работы с документами Unicode нужны соответствующие шрифты. Как правило, файл шрифта Unicode содержит начертания не для всех символов, определенных в стандарте, а лишь для символов из некоторых областей.

    Unicode в Windows NT

    Ядро Windows NT, ее графический интерфейс (GDI) и файловая система NTFS реализованы с использованием Unicode. Программы, запущенные в среде NT, могут работать также с однобайтовыми символами, кодировка которых в этом случае соответствует установленной по умолчанию кодовой странице ANSI (для России — Windows Cyrillic, или CP 1251).

    Перед вызовом некоторых функций программного интерфейса NT программы, работающие с кодовой страницей ANSI, преобразуют однобайтовые символы в Unicode. Чтобы преобразование выполнялось без ошибок, пользователь должен правильно указать страну в приложении Regional Settings. Это необходимо также для корректной работы с национальными символами программ, запущенных в сеансе MS-DOS; они используют кодовую страницу OEM, которая не всегда совпадает со страницей Windows (в частности, для России это CP 866).

    Unicode в Windows 95

    В отличие от Windows NT, ядро и графический интерфейс Windows 95 не используют Unicode, а работают с кодовыми страницами. Однако в этой ОС предусмотрена возможность динамического изменения наборов символов и раскладок клавиатуры, что позволяет создавать документы, содержащие одновременно символы из разных наборов. Буфер обмена Windows 95 способен хранить тексты в формате CF_UNICODETEXT.

    В составе Windows 95 поставляется набор шрифтов Unicode, с которыми, в частности, могут работать программы Microsoft Office 97.

    Исследование шрифтов Unicode

    Выяснить, какие наборы символов присутствуют в том или ином шрифте Unicode, можно с помощью стандартной утилиты Character Map (таблица символов), включенной в состав Windows NT (аналогичная программа из Windows 95 не подходит). Запустите ее и выберите в списке Font шрифт Arial, а в списке Subset — набор символов Windows Characters.

    Получившаяся таблица будет повторять кодовую страницу ANSI с символами западноевропейской латиницы. Выбрав же в списке Subset строку Cyrillic, вы увидите таблицу с символами кириллицы и без символов латиницы, соответствующую кириллической области Unicode.

    Для программ, работающих с кодовыми страницами ANSI, вместо шрифта Arial будет подставлен (в зависимости от страницы, установленной в системе) Arial Cyr, Arial Baltic, Arial CE, Arial Greek и т. д.

    Чтобы увидеть, как происходит подстановка, запустите программу regedt32.exe и на странице HKEY_LOCAL_MACHINE on Local Machine в разделе SOFTWARE\Microsoft\Windows NT\Current Version раскройте папку Fonts. Вы убедитесь, что шрифтов, подобных Arial Cyr, там нет. Это виртуальные шрифты, которые создаются специально для программ, работающих с кодовыми страницами ANSI. Раскрыв папку FontSubstitutes того же раздела, можно определить, что, например, шрифт Arial Cyr образуется из шрифта Arial с использованием таблицы преобразования 204.

    Техника, применяемая в Windows 95, аналогична описанной с одним отличием: шрифты для подстановки определяются не в Реестре, а в файле win.ini (раздел FontSubstitutes).

    Работа с символами Unicode

    Использование Unicode значительно упрощает создание многоязычных приложений. Поэтому, создавая программы с прицелом на этот стандарт, вы закладываете неплохую базу для локализации своего программного продукта. Ниже мы опишем работу с символами Unicode в среде Windows на языке Си (примеры проверялись с пакетом Microsoft Visual C++ 4.0 под управлением Windows NT 4.0 и Windows 95).

    Определение символьных данных Unicode

    Переменные

    Для обычных символьных данных — символов ANSI — в языке Си используется тип char; переменная этого типа занимает в памяти один байт. Для хранения символов Unicode необходимо два байта, из-за чего их называют широкими символами (wide characters). В языке Си им соответствует тип wchar_t, с которым связаны макрокоманды WCHAR и TCHAR, описанные в файле winnt.h. При определении данных Unicode рекомендуется пользоваться не непосредственно типом wchar_t, а макрокомандами.

    Макрокоманда WCHAR определена:
    typedef wchar_t WCHAR;

    Макрокоманда TCHAR универсальная, она позволяет определять как символы Unicode, так и символы ANSI. Если в начале текста программы имеется инструкция #define UNICODE, препроцессор преобразует запись TCHAR в wchar_t, если нет — в char:

    В файле winnt.h содержатся также макрокоманды для определения указателей на символы Unicode и универсальные макрокоманды (на базе TCHAR), с помощью которых можно создавать указатели на символы как ANSI, так и Unicode. Эти макрокоманды обеспечивают корректную работу при выполнении арифметических операций над указателями и при использовании указателей для индексации массивов символов Unicode.

    Модифицируя исходный текст своей программы для работы с Unicode, замените типы данных char, char*, а также LPSTR и LPCSTR соответствующими макрокомандами для Unicode. Кроме того, проверьте, не пользуетесь ли вы где-нибудь тем обстоятельством, что символ занимает в памяти один байт, и если да, внесите необходимые исправления.

    Константы

    Литеральные константы, соответствующие символам Unicode, записываются как обычные символьные константы, только с префиксом L:

    Универсальная макрокоманда TEXT позволяет определять символьные константы как двух- или однобайтовые в зависимости от того, работает ли программа с Unicode или нет:

    При наличии в тексте программы инструкции #define UNICODE такая запись будет преобразована в определение константы Unicode (с префиксом L), а при ее отсутствии — в определение обычной символьной константы.

    Специальные символы

    Символьная строка ANSI закрывается нулевым байтом, а строка Unicode — 16-разрядным нулем. Для обозначения конца такой строки можно использовать запись TEXT(‘\0’).

    Код символов CR (возврат каретки) и LF (перевод строки) в Unicode соответственно 0x000D и 0x000A (в кодировке ASCII — 0x0D и 0x0A); не заменяйте их последовательность на символ с кодом 0x0D0A. В Unicode определены также символы разделения строк (0x2028) и абзацев (0x2029).

    Символы с кодами 0xFEFF и FFEF служат сигнатурами текстовых файлов Unicode; о них мы подробнее расскажем в конце статьи.

    Функции Win32 и Unicode

    Большинство прототипов функций Win32, получающих в качестве параметров текстовые строки или символы, реализованы как макрокоманды. В зависимости от наличия в тексте программы инструкции #define UNICODE препроцессор Си подставляет вместо имени макрокоманды имя функции с суффиксом W (для Unicode) или A (для однобайтовых символов).

    Благодаря этому большинством стандартных библиотечных функций Cи можно пользоваться в программах, работающих с Unicode, точно так же, как в программах, работающих с символами ANSI. Это, в частности, относится к функциям для работы со строками, такими как strcat и printf.

    Однако есть и исключения; например, функции atoi и atol всегда ожидают строку символов ANSI, так что перед обращением к ним строка Unicode должна быть преобразована. И разумеется, во всех случаях необходимо следить за правильностью передачи параметров.

    Рассмотрим в качестве примера известную функцию MessageBox, которая выводит на экран простейшую диалоговую панель с сообщением. В файле winuser.h для нее имеется два прототипа — MessageBoxA и MessageBoxW.

    Текст программы MsgUni, работающей с Unicode и вызывающей функцию MessageBox, приведен в листинге.

    Вывод диалоговой панели с русским текстом в кодировке Unicode

    Если же заменить корректное определение строковой константы
    TCHAR szAppTitle[] = TEXT("Привет!");
    на
    char szAppTitle[] = "Привет!";
    (в листинге оно закрыто знаком комментария), то MessageBox вместо ожидаемой строки Unicode получит строку ANSI и выведет в окне нечитаемый текст. Подобные ошибки часто возникают при модификации программ для работы с Unicode.

    Вот некоторые функции программного интерфейса Win32, полезные при работе с Unicode.

    Функции GetACP и GetOEMCP возвращают номера установленных в Windows кодовых страниц ANSI и OEM, которые нужны для корректного преобразования символов ANSI в Unicode.

    Функция GetTextCharset сообщает идентификатор набора Unicode для заданного контекста отображения. Более подробную информацию о шрифте Unicode можно получить при помощи функции GetTextCharsetInfo.

    Функции mbstowcs и MultiByteToWideChar преобразуют строку однобайтовых символов в строку Unicode, функции wcstombs и WideCharToMultiByte выполняют обратное преобразование.

    Выбор шрифта для контекста отображения

    Рассмотрим способы отображения символов кириллицы на примере программы WINDOW, сокращенный текст которой приведен в листинге 2. Программа выводит в своем окне номер и название установленного в системе набора символов, затем название текущего шрифта и строку символов «AaBbCc АаБбВв». В окне есть меню Font, позволяющее выбрать для этого сообщения шрифт и набор символов.

    Вообще говоря, стандартная диалоговая панель Windows для выбора шрифта, которую открывает наша программа при выборе в меню Font пункта Select font, содержит в правом нижнем углу поле Script, позволяющее выбрать набор символов для заданного шрифта. Однако нам необходима непосредственная работа с наборами символов, поэтому мы реализовали в программе специальное меню Font.

    Для выбора шрифта в программе применяется функция ChooseFont, которая берет необходимую ей информацию из структуры типа CHOOSEFONT. Эта структура содержит поле с именем lpLogFont, указывающее, в свою очередь, на структуру типа LOGFONT. Номер набора символов задается в поле lfCharSet структуры LOGFONT. Программа работает с четырьмя наборами: ANSI_CHARSET, OEM_ CHARSET, RUSSIAN_CHARSET и DEFAULT_CHARSET.

    Описанная картина, возможно, покажется знакомой тем, кто имеет опыт программирования в Windows 3.1. Однако если в Windows 3.1 можно работать с русскими буквами, задав набор символов ANSI_CHARSET или DEFAULT_CHARSET, то здесь, как мы сейчас убедимся, ситуация совершенно иная.

    Откомпилируйте программу WINDOW в двух вариантах — с инструкцией #define UNICODE и без нее. Первый вариант, рассчитанный на Unicode, можно будет запускать только под управлением Windows NT, второй, работающий с символами ANSI, — и под управлением Windows NT, и под управлением Windows 95.

    Начнем наши эксперименты с ANSI-программы. Запустим ее и выберем шрифт Courier New. Символы кириллицы отобразятся неправильно. Почему?

    Запустив утилиту Character Map, несложно определить, что Courier New — это шрифт Unicode. Следовательно, ANSI-программа не может работать с ним непосредственно, и система строит на основе Courier New виртуальный шрифт для кодовой страницы, которая определяется набором символов, выбранным для данного контекста отображения. Поскольку мы не заказывали никакой конкретный набор, шрифт был построен для набора DEFAULT_CHARSET, не содержащего символов кириллицы. Отметим, что DEFAULT_CHARSET никак не связан с набором символов, установленным в системе (в нашем случае — кириллическим), хотя это и можно было бы предположить, исходя из его названия.

    Если выбрать тот же шрифт, предварительно отметив в меню Font строку RUSSIAN_CHARSET, русские буквы появятся, поскольку система построит заказанный ей виртуальный шрифт на основе кириллического набора. Более того, если выбрать шрифт, не содержащий символов кириллицы, система попытается подобрать ближайший эквивалент, в котором эти символы присутствуют. Что же касается набора ANSI_CHARSET, то для него, как и для DEFAULT_CHARSET, будет построен шрифт без кириллицы. Таким образом, единственный надежный способ получить кириллицу в ANSI-программе, при том что шрифт построен по стандарту Unicode, — это задать в поле lfCharSet структуры LOGFONT значение RUSSIAN_CHARSET.

    Запустим теперь Unicode-программу. Как легко убедиться, она правильно выводит кириллицу независимо от того, какой набор символов задать в меню Font (если, конечно, выбран шрифт Unicode, содержащий кириллицу). Оно и понятно: программа работает непосредственно с Unicode-шрифтом, а набор символов, который нужен для построения виртуального шрифта, здесь никак не используется.

    Однако картина кардинально изменится при выборе шрифта Baltica, разработанного для Windows 3.1. Программа ANSI будет правильно выводить русские буквы независимо от заданного набора символов, а программа Unicode не будет их выводить вообще. Правда, если в последнем случае заранее отметить в меню Font строку RUSSIAN_CHARSET, русские буквы появятся, но шрифт будет другим (например, MS Sans Serif).

    Дело в том, что в шрифте Baltica, подготовленном в старом формате, кириллическая область Unicode не представлена. В результате ANSI-программа, которая работает с этим шрифтом непосредственно (т. е. без построения виртуального шрифта), показывает кириллицу, а Unicode-программа — нет.

    Этот эффект, несомненно, знаком многим пользователям Office 97. В программах Office 97 (и для Windows NT, и для Windows 95) последовательно проведено представление всей текстовой информации в Unicode. Поэтому если, например, открыть в Word 97 документ, подготовленный в Word 6 или 7 с использованием старых шрифтов, вместо русских букв в окне появятся квадратики: так обозначается отсутствие в выбранном шрифте нужного символа. Единственный возможный выход здесь — изменить шрифт на соответствующий стандарту Unicode.

    Перекодирование однобайтовых символов в Unicodе и обратно

    Для перекодирования символов из ANSI в Unicode и обратно служат, как уже упоминалось, четыре функции: mbstowcs и MultiByteToWideChar преобразуют строку однобайтовых символов в строку Unicode, а wcstombs и WideCharToMultiByte выполняют обратное преобразование (mbstowcs и wcstombs — это функции стандартной библиотеки Си, а MultiByteToWideChar и WideCharToMultiByte — функции программного интерфейса Win32).

    Функции mbstowcs и wcstombs принимают по три параметра: указатель на буфер, в который будет записан результат перекодирования, указатель на исходную строку и число перекодируемых символов. Тем самым они никак не учитывают при преобразовании набор символов, а значит, ими можно пользоваться лишь в самом простом случае (фактически их корректная работа гарантирована лишь при условии, что все символы относятся к набору Latin 1).

    В более сложных ситуациях (в частности, если предполагается работа с кириллицей) следует использовать функции MultiByteToWideChar и WideCharToMultiByte.

    У функции MultiByteToWideChar пять параметров. Первый — это номер кодовой страницы для исходной строки. Страницу можно задать как непосредственно, так и константой типа CP_ACP (установленная в системе кодовая страница ANSI), CP_OEMCP (установленная в системе страница OEM), CP_THREAD_ACP (страница текущего потока). Второй параметр — набор флагов, определяющий способ обработки диакритик (надстрочных и подстрочных знаков) и неправильных символов. Флаг MB_PRECOMPOSED означает, что базовый символ и диакритика объединены, несовместимый с ним флаг MB_COMPOSITE — что диакритики записаны как отдельные символы. Флаг MB_ERR_INVALID_CHARS задает проверку корректности символов в исходной строке. Оставшиеся параметры определяют адрес и длину входной и выходной строк.

    Функция WideCharToMultiByte дополнительно к перечисленным принимает еще два параметра, которые нужны, если применяется обработка неправильных символов.

    В листинге 3 приводится текст простейшей программы txt2uni, перекодирующей текстовые файлы из ANSI в Unicode. Программа открывает файл в двоичном режиме и считывает его по байтам в символьную переменную ch. Для каждого байта вызывается функция mbstowcs или MultiByteToWideChar (вы можете попробовать любую), а результат перекодирования помещается в переменную wch типа wchar_t, после чего записывается в выходной файл функцией fputwc, специально предназначенной для работы с символами Unicode.

    Листинг 4 содержит текст аналогичной программы uni2txt.c, преобразующей файл Unicode в текстовый файл ANSI. Это Unicode-программа, ее первая строка представляет собой инструкцию #define UNICODE. Вместо привычной вам функции main использована функция wmain, которая получает параметры в виде строк Unicode. Таким образом, путь к исходному файлу передается функции _wfopen как строка Unicode.

    Для открытия исходного файла применяется функция _wfopen, а для считывания из него — функция fgetwc; обе они предназначены специально для Unicode-программ.

    В самое начало выходного файла программа txt2uni записывает байты 0xFF и 0xFE. Это сигнатура, определяющая порядок следования байтов в символах Unicode. Байты следуют в том же порядке, что и разряды в машинном слове на той компьютерной платформе, где создается файл. Для процессоров Intel, где первым идет самый младший бит, сигнатура имеет значение 0xFEFF. Противоположному порядку (первый бит — старший), применяемому, например, в компьютерах Macintosh, соответствует сигнатура 0xFFEF.

    Программа uni2txt проверяет сигнатуру и, если она не равна 0xFEFF, завершается с ошибкой. В чуть более сложном варианте программа могла бы осуществлять необходимую перестановку.

    Работа с набором символов

    Перекодирование однобайтовых символов в Unicode

    Перекодирование символов Unicode в однобайтовые

    Размещено с разрешения редакции журнала МИР ПК