Next Previous Contents

18. Расширение Символов

Ряд языков использует наборы символов, которые больше чем набор значений типа char.

Японский и Китайский - возможно наиболее близкие примеры.

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

На поведение функций в этой главе воздействует текущий стандарт для символьной классификации LC_CTYPE класса; см. Раздел 19.3 [Категории Стандарта]. Этот стандарт указывает, который многобайтовый код используется, и также управляет значениями и характеристиками расширенных символьных кодов.

18.1 Введение в Расширение Символов

Вы можете представлять расширенные символы одним из двух способов:

Преимущество расширенных символов - то, что каждый символ является одиночным объектом данных, точно так же как обычные символы ASCII. Имеются несколько недостатков: Обычно, Вы используете многобайтовое символьное представление как часть внешнего интерфейса программы, типа чтения или запииси в файлы. Однако, обычно проще выполнить внутренние манипулирования на строках, содержащих расширенные символы, в массивах объектов wchar_t, так как однородное представление делает операции редактирования намного проще. Если Вы используете многобайтовые символы для файлов и расширенные символы для внутренних операций, Вы должен преобразовать их при записи и чтении данных.

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

18.2 Стандарты и Расширенные Символы

Компьютерная система может поддерживать больше чем один многобайтовый символьный код, и больше чем один расширенный символьный код. Пользователь управляет выбором кодов через текущий стандарт для символьной классификации (см. Главу 19 [Стандарты] ). Каждый стандарт определяет специфический многобайтовый символьный код и специфический расширенный символьный код. Выбор стандарта влияет на поведение функций преобразования в библиотеке.

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

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

18.3 Многобайтовые Символы

В обычном коде ASCII, последовательность символов ­ последовательность байтов, и каждый символ - один байт. Это очень просто, но учитывает только 256 различных символов.

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

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

Эти последовательности не имеют одинаковую длину. Фактически, многие из их - только один байт. Потому что базисные символы ASCII в промежутке от 0 до 0177 настолько важны, что они замещают себя во всех многобайтовых символьных кодах. То есть байт, чье значение от 0 до 0177 - всегда символ сам по себе. Символы, которые больше чем один байт, должны всегда начинаться с байта в промежутке от 0200 до 0377.

Значение 0 байта может использоваться, чтобы завершить строку, точно как это часто используется в строке символов ASCII.

Определение базисных последовательностей байтов, которые представляют одиночные символы автоматически дают значения более длинным последовательностям байтов, больше чем один символ. Например, если последовательность два байта 0205 049 замещает символ греческой альфы, то 0205 049 065 должна заместить альфу, сопровождаемую " " (код ASCII 065), а 0205 049 0205 049 должна заместить две альфы в строке.

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

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

Самый простой возможный многобайтовый код - тривиальный:

Базисные последовательности состоят из одиночных байтов.

Данный специфический код не использует многобайтовые символы вообще. Он не имеет никаких недопустимых последовательностей. Но он может обрабатывать только 256 различных символов.

Вот другой возможный код, который может обрабатывать 9376 различных символов:

Базисные последовательности состоят из

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

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

Базисные последовательности состоят из

В этом коде, любая последовательность, которая начинается с байта в промежутке от 0240 до 0377, недопустима.

Вот другой вариант, который имеет преимущество: при удалении последнего байта или байтов допустимого символа, никогда не может появиться другой допустимый символ.

Базисные последовательности состоят из

Список недопустимых последовательностей для этого кода ­ довольно длинный и не стоит полного просмотра; примеры недопустимых последовательностей включают 0240 и 0220 0300 065.

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

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

       int MB_LEN_MAX  (макрос)
Это - максимальная длина многобайтового символа для любого обеспечиваемого стандарта. Она определена в " limits.h ".
       int MB_CUR_MAX  (макрос)
Эта макрокоманда отображает (возможно не-константу) положительное целочисленное выражение, которое является максимальным числом байтов в многобайтовом символе в текущем стандарте. Значение никогда не большее чем MB_LEN_MAX.

MB_CUR_MAX определен в " stdlib.h ".

Что случается, если Вы пробуете передавать строку, содержащую многобайтовые символы функции, которая не знает о них? Обычно, такая функция обрабатывает строку как последовательность байтов, и интерпретирует некоторые значения особенно; все другие значения байтов "обычны". Если многобайтовый символ не содержит специальное значение байта, функция должна обработать его, как будто это были отдельные обычные символы.

18.4 Введение в Расширенные Символы

Расширенные символы намного проще чем многобайтовые символы. Они - просто символы с больше, чем восемью битами, так, чтобы они имели место для больше, чем 256 различных кодов. Расширенный символьный тип данных wchar_t, имеет достаточно большой диапазон, чтобы содержать расширенные символьные коды также как традиционные коды ASCII.

Преимущество расширенных символов - в том, что каждый символ является одиночным объектом данных, точно так же как обычные символы ASCII. Эти символы также имеют некоторые недостатки:

Расширенные символьные значения от 0 до 0177 всегда идентичны кодам символов ASCII. Расширенный нуль часто используется, чтобы завершить строку расширенных символов, точно как, одиночный нулевой байт часто завершает строку обычных символов.
       wchar_t  (тип данных)
Это - тип " расширенных символов " , целочисленный тип, чей диапазон достаточно велик, чтобы представить все различные значения в любом расширенном наборе символов в обеспечиваемых стандартах. См. Главу 19 [Стандарты], для получения более подробной информации. Этот тип определен в заглавном файле " stddef.h ".

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

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

18.5 Преобразование Расширенных Строк

Функция mbstowcs преобразовывает строку многобайтовых символов в массив расширенных символов. Функция wcstombs делает обратный процесс. Эти функции объявлены в заглавном файле " stdlib.h ".

В большинстве программ, эти функции - единственная Ваша потребность в преобразовании между расширенными строками и многобайтовыми символьными строками. Но они имеют ограничения. Если ваши данные не с нулевым символом в конце или - не все в ядре сразу, Вы возможно должны использовать функции преобразования низкого уровня, чтобы преобразовать один символ за раз. См. Раздел 18.7 [Преобразование Одного Символа].

       size_t mbstowcs (wchar_t *wstring, const char *string, size_t size)
mbstowcs (" многобайтовая строка в строку расширенных символов ") функция преобразовывает строку с нулевым символом в конце многобайтовых символов в массив расширенных символов, сохраняя не больше чем size расширенных символов в массиве, начинающемся в wstring. Пустой символ завершения рассчитывается в size, так что, если размер меньше, чем фактическое число расширенных символов, следующих из строки, никакой пустой символ завершения не будет сохранен.

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

Если недопустимая многобайтовая символьная последовательность найдена, функция возвращает значение -1. Иначе, она возвращает число расширенных символов, сохраненных в массиве wstring. Это число не включает пустой символ завершения, который присутствует, если число меньше, чем size.

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

         wchar_t *
         mbstowcs_alloc (const char *string)
         {
                 size_t size = strlen (string) + 1;
                 wchar_t *buf = xmalloc (size * sizeof (wchar_t));
                 size = mbstowcs (buf, string, size);
                 if (size == (size_t) -1)
                         return NULL;
                 buf = xrealloc (buf, (size + 1) * sizeof (wchar_t));
                 return buf;
         }
       size_t wcstombs (char *string,const wchar_t wstring,size_t size)
wcstombs преобразует массив расширенных символов с нулевым символом в конце в строку, содержащую многобайтовые символы, сохраняя не больше чем size байт, начиная с string.

Если найден код, который не соответствует допустимому многобайтовому символу, то эта функция возвращает значение -1. Иначе, возвращаемое значение - число байтов, сохраненных в массиве. Это число не включает пустой символ завершения, который присутствует, если число - меньше чем size.

18.6 Длина Многобайтового Символа

Этот раздел описывает, как просмотреть строку, содержащую многобайтовые символы, по одному символу. Трудность в том, что нужно знать, сколько байтов каждый символ содержат. Ваша программа может использовать mblen, чтобы узнать это.

       int mblen (const char *string, size_t size) 
Функция mblen с непустым аргументом string возвращает число байтов, которые составляют многобайтовый символ, начинающийся с string, никогда не исследуя больше size байт. (Идея состоит в том, чтобы обеспечить для size число байтов данных, которые Вы имеете.)

Возвращаемое значение mblen отличает три возможности: первые size байт строки начинаются с допустимого многобайтового символа, они начинаются с недопустимой последовательности байтов или включают только часть символа, или string указывает на пустую строку (пустой символ).

Для допустимого многобайтового символа, mblen возвращает число байтов в этом символе (всегда по крайней мере 1, и никогда не больше чем size). Для недопустимой последовательности байтов, mblen возвращает -1. Для пустой строки, она возвращает 0.

Если многобайтовый символьный код использует символы смены регистра, то mblen, поддерживает и модифицирует параметр регистра. Если Вы вызываете mblen с пустым указателем для строки, она инициализирует параметр регистра к стандартному начальному значению. См. Раздел 18.9 [Параметра Регистра] .

Функция mblen объявлена в " stdlib.h ".

18.7 Преобразование Расширенных Символов по Одному

Вы можете преобразовывать многобайтовые символы в расширенные символы по одному mbtowc функцией. Wctomb функция делает обратное. Эти функции объявлены в " stdlib.h ".

       int mbtowc (wchar_t *result, const char *string, size_t size)
Mbtowc преобразовывает первый многобайтовый символ в string в соответствующий расширенный символьный код. Она сохраняет результат в *result. Mbtowc никогда не исследует больше чем size байт. (Идея состоит в том, чтобы обеспечить для size число байтов данных, которое Вы имеете.) Mbtowc с непустой строкой Возвращаемое значение mblen отличает три возможности: первые size байт строки начинаются с допустимого многобайтового символа, они начинаются с недопустимой последовательности байтов или включают только часть символа, или string указывает на пустую строку (пустой символ).

Для допустимого многобайтового символа, mbtowc преобразовывает его в расширенный символ, сохраняет его в *result, и возвращает число байтов в том символе (всегда по крайней мере 1, и никогда не болольше чем size).

Для недопустимой последовательности байтов, mbtowc возвращает ­ 1. Для пустой строки, она возвращает 0, также сохраняя 0 в *result.

       int wctomb (char *string, wchar_t wchar)  
Функция wctomb преобразует расширенный символьный код wchar в соответствующую многобайтовую символьную последовательность, и сохраняет результат в байтах, начиная с string. Wctomb с непустой строкой отличает три возможности для wchar: допустимый расширенный символьный код (тот, который может транслироваться в многобайтовый символ), недопустимый код, и 0.

Если wchar - недопустимый расширенный символьный код, wctomb возвращает -1. Если wchar - 0, она возвращает 0, также сохраняя 0 в *string.

Вызов этой функции с нулевым wchar аргументом, когда строка - не пустой символ, имеет побочный эффект переинициализации сохраненного параметра регистра также как сохранения многобайтового символа 0 и возвращения 0.

18.8 Пример Посимвольного Преобразования

Вот пример, который читает многобайтовоый-символьный текст из дескриптора input и записывает соответствующие расширенные символы в описатель output. Мы должны преобразовать символы один за другим в этом примере, потому что mbstowcs неспособна продолжиться после пустого символа, и не может справляться с очевидно недопустимым частичным символом, читая большое количество ввода.

                 int
                 file_mbstowcs (int input, int output)
                 {
                         char buffer[BUFSIZ + MB_LEN_MAX];
                         int filled = 0;
                         int eof = 0;
                         while (!eof)
                         {
                                 int nread;
                                 int nwrite;
                                 char *inp = buffer;
                                 wchar_t outbuf[BUFSIZ];
                                 wchar_t *outp = outbuf;
                                 nread = read (input, buffer +
                         filled, BUFSIZ);
                                 if (nread < 0)
                                 {
                                         perror ("read");
                                         return 0;
                                 }
                                 if (nread == 0)
                                         eof = 1;
                                 filled += nread;
                                 while (1)
                                 {
                                         int thislen = mbtowc (outp,
                                         inp, filled);
                                         if (thislen == -1)
                                                 break;
                                         if (thislen == 0) {
                                                 thislen = 1;
                                                 mbtowc (NULL, NULL, 0);
                                         }
                                         inp += thislen;
                                         filled -= thislen;
                                         outp++;
                                 }
                                 nwrite = write (output, outbuf,
                                         (outp-outbuf)*sizeof(wchar_t));
                                 if (nwrite < 0)
                                 {
                                         perror ("write");
                                         return 0;
                                 }
                                 if ((eof && filled > 0) ||
                 filled >= MB_CUR_MAX)
                                 {
                                         error ("invalid
                 multibyte character");
                                         return 0;
                                 }
                                 if (filled > 0)
                                         memcpy (inp, buffer, filled);
                         }
                         return 1;
                 }

18.9 Многобайтовые Коды, использующие Последовательности Регистров

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

Чтобы проиллюстрировать состояние регистра и последовательности регистров, предположите, что мы устанавливаем, что последовательность 0200 (только один байт) вводит Японский режим, в котором пары байтов в промежутке от 0240 до 0377 являются одиночными символами, в то время как 0201 вводит Латинский-1 режим, в котором одиночные байты в промежутке от 0240 до 0377 являются символами, и интерпретируются согласно набору символов Latin-1 Международной организации по стандартизации. Это - многобайтовый код, который имеет два альтернативных состояния регистра ("Японский режим " и " Латинский-1 режим "), и две последовательности регистров, которые определяют специфические состояния регистра.

Когда используемый многобайтовый символьный код имеет состояния регистра, то mblen, mbtowc и wctomb должны поддерживать и модифицировать текущее состояние регистра, поскольку они просматривают строку. Чтобы делать эту работу правильно, Вы должны следовать этим правилам: * Перед стартом просмотра строки, вызовите функцию с пустым указателем для многобайтового символьного адреса например, mblen (NULL, 0). Это инициализирует состояние регистра к стандартному начальному значению. * Просматривайте строку по одному символу. Не "возвращайтесь" и не перепросмотривайте уже просмотренные символы, и не смешивайте обработку различных строк.

Вот пример использования mblen с соблюдением этих правил:

                         void
                         scan_string (char *s)
                         {
                                 int length = strlen (s);
                                 mblen (NULL, 0);
                                 while (1)
                                 {
                                         int thischar = mblen (s, length);
                                         if (thischar == 0)
                                                 break;
                                         if (thischar == -1)
                                         {
                                                 error ("invalid multibyte
                                                         character");
                                                                         break;
                                         }
                                         s += thischar;
                                         length -= thischar;
                                 }
                         }
Функции mblen, mbtowc и wctomb не используются при использовании многобайтового кода, который использует состояние регистра. Однако, никакие другие библиотечные функции не вызывают эти функции, так что Вы не должны волноваться относительно этого.


Next Previous Contents