Данный раздел содержит информацию о функциях работы с многобайтовыми и широкими символьными кодами. Ниже перечислены главные темы этого раздела:
В среде с поддержкой национальных языков функции обработки многобайтовых и широких символов не различаются. Решение о том, какие именно функции использовать, следует принимать только после тщательного анализа.
Если в программе применяются в основном функции обработки многобайтовых символов, то, возможно, перед применением определенных функций обработки широких символов коды многобайтовых символов придется преобразовать в коды широких символов. Если, наоборот, в программе используются функции обработки широких символов, то при вызове функций может потребоваться преобразовать данные в многобайтовую форму. У обоих способов есть недостатки, в зависимости от конкретной программы и применяемых библиотечных функций. Например, у функции определения ширины широкого символа нет многобайтового аналога.
Если программа может обрабатывать свои символы в многобайтовой форме, то следует выбрать именно этот способ, а не преобразовывать символы в широкую форму.
Внимание: Преобразование между многобайтовым кодом и кодом широких символов определяется текущей локалью. Нельзя выполнять обмен широкими символами между двумя процессами, если вы не уверены, что каждая из используемых локалей правильно интерпретирует их. Большинство локалей AIX воспринимают символы Unicode как широкие символы, за исключением локалей, основанных на кодовых наборах IBM-850 и IBM-eucTW.
При преобразовании многобайтовых
символов в широкие символы применяются следующие функции:
mblen | Вычисляет длину многобайтового символа. |
mbstowcs | Преобразует строку многобайтовых символов в строку широких символов. |
mbtowc | Преобразует многобайтовый символ в широкий символ. |
При преобразовании широких
символов в многобайтовые символы применяются следующие функции:
wcslen | Определяет число широких символов в строке. |
wcstombs | Преобразует строку широких символов в строку многобайтовых символов. |
wctomb | Преобразует широкий символ в многобайтовый символ. |
main() { char *s; wchar_t wc; int n; (void)setlocale(LC_ALL,""); /* ** s указывает на строку символов, преобразуемую ** в широкий символ, который будет храниться в wc. */ n = mbtowc(&wc, s, MB_CUR_MAX); if(n == -1){ /* Обработка ошибок */ } if (n == 0){ /* указатель на пустую строку */ } /* ** wc содержит код процесса для многобайтового символа, ** на который указывает s. */ }
#include <stdlib.h> #include <limits.h> /* для MB_LEN_MAX */ #include <stdlib.h> /* для wchar_t */ main() { char s[MB_LEN_MAX}; /* системное значение для максимального числа ** байт в многобайтовом символе r. */ wchar_t wc; int n; (void)setlocale(LC_ALL,""); /* ** wc - это код широкого символа, преобразуемый ** в код многобайтового символа. */ n = wctomb(s, wc); if(n == -1){ /* pwcs не указывает на допустимый широкий символ */ } /* ** n содержит длину многобайтового символа, ** хранящегося в s, в байтах. */ }
#include <stdlib.h> #include <locale.h> main { char *name = "h"; int n; (void)setlocale(LC_ALL,""); n = mblen(name, MB_CUR_MAX); /* ** Число, возвращаемое в n, равно длине многобайтового символа. ** Оно всегда меньше или равно значению ** MB_CUR_MAX из stdlib.h */ if(n == -1){ /* Обработка ошибок */ } }
char buf[]; /* содержит строку многобайтовых символов */ char *cur, /* указывает на позицию текущего символа */ char *prev, /* указывает на позицию предыдущего символа */ char *p; /* перемещающийся указатель */ /* по мере необходимости инициализируйте буфер и указатели */ /* выполняйте цикл перебора символов в буфере, пока перемещающийся указатель ** не достигнет позиции текущего символа в буфере; позиция последнего ** символа всегда сохраняется в указателе prev */ p = prev = buf; /* cur указывает на допустимый символ, находящийся в буфере */ while(p< cur){ prev = p; if( (i=mblen(p, mbcurmax))<=0){ /* недопустимый многобайтовый или пустой символ */ /* Вы можете применять другую стратегию обработки ** ошибок */ p++; /* пропустить его */ }else { p += i; } } /* prev будет указывать на позицию предыдущего символа */ /* Заметим, что если ( prev == cur ), то это означает, что ** предыдущего символа нет. Кроме того, если все символы вплоть до ** текущего являются недопустимыми, все они будут рассматриваться как ** обычные однобайтовые символы, а это может быть совсем не то, что вам ** нужно. Такой порядок обработки можно изменить, выбрав другой ** способ исправления ошибок.
#include <stdlib.h> #include <locale.h> main() { char *s; wchar_t *pwcs; size_t retval, n; (void)setlocale(LC_ALL, ""); n = strlen(s) + 1; /*string length + terminating null */ /* Allocate required wchar array */ pwcs = (wchar_t *)malloc(n * sizeof(wchar_t) ); retval = mbstowcs(pwcs, s, n); if(retval == -1){ /* Обработка ошибок */ } /* ** pwcs содержит строку широких символов. */ }
Примечание: Такой способ обработки значительно замедляет выполнение программы.При преобразовании однобайтовых кодовых наборов нет возможности обрабатывать неполные многобайтовые символы. Однако при преобразовании многобайтовых кодовых наборов неполные многобайтовые символы копируются в буфер сохранения. При следующем вызове функции read неполный многобайтовый символ присоединяется к началу последовательности остальных байтов.
Примечание: Возвращается строка широких символов, оканчивающаяся символом NULL. При обнаружении недопустимой последовательности байт может быть выполнена дополнительная обработка ошибок.
#include <stdio.h> #include <locale.h> #include <stdlib.h> main(int argc, char *argv[]) { char *curp, *cure; int bytesread, bytestoconvert, leftover; int invalid_multibyte, mbcnt, wcnt; wchar_t *pwcs; wchar_t wbuf[BUFSIZ+1]; char buf[BUFSIZ+1]; char savebuf[MB_LEN_MAX]; size_t mb_cur_max; int fd; /* ** MB_LEN_MAX определяет системную константу, задающую ** максимальное число байт в многобайтовом символе. */ (void)setlocale(LC_ALL, ""); mb_cur_max = MB_CUR_MAX; fd = open(argv[1], 0); if(fd < 0){ /* обработка ошибок */ } leftover = 0; if(mb_cur_max==1){ /* Случай наборов однобайтовых символов */ for(;;) { bytesread = read(fd, buf, BUSIZ); if(bytesread <= 0) break; mbstowcs(wbuf, buf, bytesread+1); /* Обработка с использованием буфера с широкими символами */ } /* Обрабатываемый файл ... */ exit(0); /* Конец программы */ }else{ /* Наборы многобайтовых символов */ leftover = 0; for(;;) { if(leftover) strncpy(buf, savebuf ,leftover); bytesread=read(fd,buf+leftover, BUFSIZ-leftover); if(bytesread <= 0) break; buf[leftover+bytesread] = '\0'; /* Символ конца строки (NULL) */ invalid_multibyte = 0; bytestoconvert = leftover+bytesread; cure= buf+bytestoconvert; leftover=0; pwcs = wbuf; /* Завершение обработки при обнаружении недопустимого */ /* многобайтового символа. */ curp= buf; for(;curp<cure;){ mbcnt = mbtowc(pwcs,curp, mb_cur_max); if(mbcnt>0){ curp += mbcnt; pwcs++; continue; }else{ /* Дополнительные данные, необходимые при следующем чтении */ if ( cure-curp<mb_cur_max){ leftover=cure-curp; strncpy(savebuf,curp,leftover); /* Добавление символа NULL перед неполным многобайтовым */ /* символом */ *curp=0; break; }else{ /* Обнаружен недопустимый многобайтовый символ */ invalid_multibyte =1; break; } } } if(invalid_multibyte){ /* обработка ошибок */ } /* Обработка буфера с широкими символами */ } } }
#include <stdlib.h> #include <locale.h> main() { wchar_t *pwcs; /* Исходная строка широких символов */ char *s; /* Целевая строка многобайтовых символов */ size_t n; size_t retval; (void)setlocale(LC_ALL, ""); /* ** Вычисляется максимальное число байт, необходимое для хранения ** буфера широких символов в многобайтовом виде в текущей кодовой ** странице, и с помощью функции malloc() выделяется необходимая ** память (включая символ конца строки NULL). */ s = (char *) malloc( wcslen(pwcs) * MB_CUR_MAX + 1 ); retval= wcstombs( s, pwcs, n); if( retval == -1) { /* Обработка ошибок */ /* s указывает на строку многобайтовых символов. */ }
Большинство функций классификации широких символов аналогичны функциям классификации обычных символов, за исключением того, что первые работают с аргументом типа wchar_t, передаваемым как аргумент типа wint_t.
В среде с поддержкой национальных языков важную роль играет возможность создания новых свойств классов символов. Например, для символов японского языка определены некоторые свойства, не применимые к символам английского языка. По этой причине, для поддержки большого числа языков необходима среда, позволяющая приложениям работать с различными свойствами символов. Для работы с классами символов в общей форме предназначены функции wctype и iswctype. Эти функции позволяют работать как с классами пользовательских символов, так и с классами символов конкретных языков.
Действие функций классификации широких символов зависит от значения категории LC_CTYPE текущей локали.
Для создания нового класса символов, который будет определяться функциями wctype и iswctype, необходимо задать его свойства в категории LC_CTYPE и определить локаль командой localedef. Пользовательское приложение получит данные этой локали с помощью функции setlocale. Затем программа сможет получить доступ к новым функциям классификации, используя при этом функцию wctype для получения описателя свойства wctype_t. После этого описатель свойства и код проверяемого широкого символа можно будет передать функции iswctype.
wctype | Получает описатель для классификации свойства символа. |
iswctype | Проверяет свойство символа. |
Функции isw* позволяют определить разнообразные аспекты стандартной классификации широких символов. Кроме того, функции isw* поддерживают наборы однобайтовых символов. Если это возможно, следует применять функции isw* вместо функций wctype и iswctype. Функции wctype и iswctype следует использовать только для работы с дополнительными свойствами классов символов (например, со свойствами японского языка).
Если функции обработки широких символов применяются для преобразования регистра в нескольких блоках данных, то приложение должно преобразовывать многобайтовые символы в широкие символы. Поскольку это может повлиять на быстродействие программы в случае локалей с однобайтовыми кодовыми наборами, в приложение необходимо предусмотреть два способа изменения регистра. Традиционный способ, применяемый для локалей с однобайтовыми кодовыми наборами, - это использование функций isupper, islower, toupper и tolower. Альтернативный способ, применяемый в локалях с многобайтовыми кодовыми наборами, заключается в том, что сначала выполняется преобразование многобайтовых символов в широкие, а затем с помощью функций iswupper, iswlower, towupper и towlower изменяется регистр. При преобразовании многобайтовых символов в широкие приложению придется обрабатывать некоторые специальные случаи, когда многобайтовый символ занимает несколько последовательных блоков.
iswalnum | Проверяет, является ли символ алфавитно-цифровым. |
iswalpha | Проверяет, является ли символ алфавитным. |
iswcntrl | Проверяет, является ли символ управляющим. |
iswdigit | Проверяет, является ли символ цифрой. |
iswgraph | Проверяет, является ли символ графическим. |
iswlower | Проверяет, относится ли символ к нижнему регистру. |
iswprint | Проверяет, является ли символ печатаемым. |
iswpunct | Проверяет, является ли символ знаком пунктуации. |
iswspace | Определяет, является ли символ пробелом. |
iswupper | Проверяет, относится ли символ к верхнему регистру. |
iswxdigit | Проверяет, является ли символ шестнадцатеричным числом. |
Ниже перечислены функции,
изменяющие регистр широких символов. Выполняемые ими действия зависят
от определений, заданных в категории LC_CTYPE
для текущей локали.
towlower | Преобразует широкий символ верхнего регистра в широкий символ нижнего регистра. |
towupper | Преобразует широкий символ нижнего регистра в широкий символ верхнего регистра. |
В следующем примере функция wctype используется для проверки принадлежности символов классу NEW_CLASS:
#include <ctype.h> #include <locale.h> #include <stdlib.h> main() { wint_t wc; int retval; wctype_t chandle; (void)setlocale(LC_ALL,""); /* ** Получение описателя свойства символа для класса ** NEW_CLASS. */ chandle = wctype("NEW_CLASS") ; if(chandle == (wctype_t)0){ /* Неверное свойство. Обработка ошибки. */ } /* Пусть wc содержит код широкого символа */ /* Проверка, обладает ли wc свойством NEW_CLASS */ retval = iswctype( wc, chandle ); if( retval > 0 ) { /* ** wc обладает свойством NEW_CLASS. */ }else if(retval == 0) { /* ** Символ, представляемый wc, не обладает свойством ** NEW_CLASS. */ } }
При выводе символов на экран или принтер число столбцов, занимаемых каждым символом, может быть различным. Например, символ канжи (японский иероглиф) может занимать несколько столбцов. Число столбцов экрана, требуемое для отображения каждого символа, задано в базе данных локали Поддержки национальных языков (NLS), в категории LC_CTYPE .
Стандартных функций для определения ширины многобайтового символа не существует. Для обеспечения переносимости приложений необходимо преобразовать многобайтовые символы в широкие и использовать функции определения ширины широких символов. Однако если в файле stdlib.h задано макроопределение, присваивающее переменной __max_disp_width значение 1, и используется кодовый набор однобайтовых символов, то все символы данного кодового набора (кроме символов табуляции) занимают по одному столбцу на экране. В этом случае число столбцов, занимаемое строкой на экране (ширина строки), определяется с помощью функции strlen (строка). Это проиллюстрировано в следующем примере:
#include <stdlib.h> int display_column_width; /* число столбцов на экране */ char *s; /* строка символов */ .... if((MB_CUR_MAX == 1) && (__max_disp_width == 1)){ display_column_width = strlen(s); /* s - это указатель на строку */ }
Для определения числа столбцов,
занимаемых строкой широких символов на экране, предназначены следующие
функции:
wcswidth | Определяет длину строки широких символов на экране. |
wcwidth | Определяет ширину широкого символа на экране. |
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wint_t wc; int retval; (void)setlocale(LC_ALL, ""); /* ** Пусть wc - это широкий символ, ширину которого ** необходимо определить. */ retval = wcwidth(wc); if(retval == -1){ /* ** Обработка ошибки. В wc обнаружен ** недопустимый или непечатаемый символ. */ } }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs; int retval; size_t n; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs - это указатель на строку широких символов, ** завершающуюся символом NULL. ** Пусть n - это число широких символов, для которых определяется ** число столбцов, занимаемое ими на экране (ширина символа). */ retval = wcswidth(pwcs, n); if(retval == -1){ /* ** Обработка ошибок. В строке широких символов pwcs ** обнаружен недопустимый или непечатаемый ** символ. */ } }
Сравнение строк может выполняться двумя способами:
В NLS (Поддержке национальных языков) применяется второй способ.
Упорядоченность - это свойство символов, определяемое локалью. Каждому символу ставится в соответствие вес, соответствующий его относительному положению в последовательности сортировки. Символу может соответствовать несколько весов, распределяемых по приоритету: основной, дополнительный, третьего уровня и т.д. Максимальное число весов, которое может быть присвоено одному символу, определяется системой.
Во время запуска процесса он наследует локаль C или локаль POSIX. При вызове функции setlocale (LC_ALL, " ") локаль, получаемая процессом, определяется переменными среды LC_* и LANG. Порядок сортировки двух строк в данной локали определяется перечисленными ниже функциями, действия которых зависят от значения категории LC_COLLATE.
Примечание: Сравнение строк на основе весов символов занимает значительное время, так как требуется запрашивать веса. Такие операции сравнения должны выполняться только в случае крайней необходимости. Если вам нужно сравнить две строки, состоящие из широких символов, не применяйте для этого функции wcscoll и wcsxfrm. Лучше воспользуйтесь функцией wcscmp.
Для весового сравнения строк
многобайтовых символов предназначены следующие функции:
strcoll | Сравнивает строки многобайтовых символов на основе весов символов. |
strxfrm | Преобразует строку многобайтовых символов в значения весов символов. |
Для весового сравнения строк
широких символов предназначены следующие функции:
wcscoll | Сравнивает строки широких символов на основе весов символов. |
wcsxfrm | Преобразует строку широких символов в значения весов символов. |
#include <stdio.h> #include <string.h> #include <locale.h> #include <stdlib.h> extern int errno; main() { wchar_t *pwcs1, *pwcs2; size_t n; (void)setlocale(LC_ALL, ""); /* обнуление errno для отслеживания ошибок в wcscoll */ errno = 0; /* ** pwcs1 и pwcs2 - две сравниваемые строки широких ** символов. */ n = wcscoll(pwcs1, pwcs2); /* ** Если errno ненулевой, то он указывает ** на ошибку сортировки. */ if(errno != 0){ /* произошла ошибка... обработка ошибки ...*/ } }
Примечание: Определить длину n преобразованной строки (n - число) при работе с функцией wcsxfrm можно одним из следующих способов:
Выбор способа зависит от характеристик строк и от требований к производительности программы.
#include <stdio.h> #include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2, *pwcs3, *pwcs4; size_t n, retval; (void)setlocale(LC_ALL, ""); /* ** pwcs1 и pwcs3 будут указывать на массивы широких ** символов, в которые будут записаны строки после ** преобразования. pwcs2 и pwcs4 будут указывать на ** строки широких символов, которые будут применяться для ** весового сравнения. ** Присвоим n достаточно большое значение (например, BUFSIZ), ** достаточное для преобразования строк pwcs2 и pwcs4. ** ** Примечание: ** На практике при сравнении строки широких символов с ** несколькими другими строками удобнее всего пользоваться ** функцией wcsxfrm. */ do { retval = wcsxfrm(pwcs1, pwcs2, n); if(retval == (size_t)-1){ /* произошла ошибка */ /* обработка ошибки */ break; } if(retval >= n ){ /* ** увеличение значения n и размера буфера pwcs1. */ } }while (retval >= n); do { retval = wcsxfrm(pwcs3, pwcs4, n); if (retval == (size_t)-1){ /* произошла ошибка */ /* обработка ошибки */ break; if(retval >= n){ /* увеличение значения n и размера буфера pwcs3.*/ } }while (retval >= n); retval = wcscmp(pwcs1, pwcs3); /* результат записан в retval */ }
Функции strcmp и strncmp определяют, одинаково ли содержимое двух строк многобайтовых символов. Если приложению необходима информация о лексических различиях между строками, воспользуйтесь функциями весового сравнения строк многобайтовых и широких символов.
Для порядкового сравнения строк
широких символов предназначены следующие функции NLS:
wcscmp | Сравнивает две строки широких символов. |
wcsncmp | Сравнивает указанное число строк широких символов. |
В следующем примере для сравнения двух строк широких символов используется функция wcscmp:
#include <stdio.h> #include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2, *pwcs3, *pwcs4; size_t n, retval; (void)setlocale(LC_ALL, ""); /* ** pwcs1 и pwcs2 будут указывать на массивы широких ** символов, в которые будут записаны строки после ** преобразования. */ retval = wcscmp(pwcs1, pwcs2); /* в pwcs1 копия строки широких символов, содержащейся ** в pwcs2 */ }
Для преобразования строк,
состоящих из широких символов, в числа двойной точности, а также длинные целые
числа со знаком или без знака предназначены следующие функции NLS:
wcstod | Преобразует строку широких символов в вещественное число двойной точности. |
wcstol | Преобразует строку широких символов в длинное целое число со знаком. |
wcstoul | Преобразует строку широких символов в длинное целое число без знака. |
Перед вызовом функции wcstod, wcstoul или wcstol необходимо присвоить глобальной переменной errno значение 0 - это позволит правильно обрабатывать все ошибки, возникающие при обращении к этим функциям.
#include <stdlib.h> #include <locale.h> #include <errno.h> extern int errno; main() { wchar_t *pwcs, *endptr; double retval; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs - это указатель на строку широких символов, ** оканчивающуюся символом NULL и содержащую вещественное число. */ errno = 0; /* обнуление errno */ retval = wcstod(pwcs, &endptr); if(errno != 0){ /* значение errno изменилось, значит, произошла ошибка */ if(errno == ERANGE){ /* значение вышло за пределы ** представимых значений. ** Ошибка - переполнение */ if((retval == HUGE_VAL) || (retval == -HUGE_VAL)){ /* Ошибка. Вызов соответствующей программы обработки */ }else if(retval == 0){ /* Ошибка - потеря значимости. */ /* Вызов программы обработки ошибок */ } } } /* retval содержит искомое число двойной точности. */ }
#include <stdlib.h> #include <locale.h> #include <errno.h> #include <stdio.h> extern int errno; main() { wchar_t *pwcs, *endptr; long int retval; (void)setlocale(LC_ALL, ""); /* ** pwcs будет указывать на строку широких символов, ** содержащую длинное целое число и завершенную ** символом NULL */ errno = 0; /* обнуление errno */ retval = wcstol(pwcs, &endptr, 0); if(errno != 0){ /* значение errno изменилось, если произошла ошибка */ if(errno == ERANGE){ /* Правильное значение находится вне диапазона ** представимых значений. Это признак ** переполнения. */ if((retval == LONG_MAX) || (retval == LONG_MIN)){ /* Ошибка. Обработка ошибки. */ }else if(errno == EINVAL){ /* Значение базы не поддерживается */ /* Обработка этой ситуации */ } } } /* в retval записано длинное целое число. */ }
#include <stdlib.h> #include <locale.h> #include <errno.h> extern int errno; main() { wchar_t *pwcs, *endptr; unsigned long int retval; (void)setlocale(LC_ALL, ""); /* ** pwcs будет указывать на строку широких символов с длинным ** целым числом без знака, завершенную символом NULL */ errno = 0; /* set errno to zero */ retval = wcstoul(pwcs, &endptr, 0); if(errno != 0){ /* произошла ошибка */ if(retval == ULONG_MAX || errno == ERANGE){ /* ** Правильное значение находится вне ** представимого диапазона. Обработка этой ситуации. */ }else if(errno == EINVAL){ /* Значение базы непредставимо */ /* Обработка этой ситуации */ } } /* В retval записано длинное целое без знака. */ }
Для копирования строк широких
символов предназначены следующие функции NLS:
wcscpy | Копирует строку широких символов в другую строку широких символов. |
wcsncpy | Копирует указанное число символов из одной строки широких символов в другую строку широких символов. |
wcscat | Добавляет одну строку широких символов к другой строке широких символов. |
wcsncat | Добавляет указанное число символов из одной строки широких символов к другой строке широких символов. |
В следующем примере для копирования строки широких символов в массив широких символов применяется функция wcscpy:
#include <string.h> #include <locale.h> #include <stdlib.h>
main() { wchar_t *pwcs1, *pwcs2; size_t n; (void)setlocale(LC_ALL, ""); /* ** Выделение памяти для массива широких символов. */ pwcs1 = (wchar_t *)malloc( (wcslen(pwcs2) +1)*sizeof(wchar_t)); wcscpy(pwcs1, pwcs2); /* ** pwcs1 содержит копию строки широких символов из pwcs2 */ }
Для выполнения поиска в строках
широких символов предназначены следующие функции NLS:
wcschr | Ищет первое вхождение широкого символа в строку широких символов. |
wcsrchr | Ищет последнее вхождение широкого символа в строку широких символов. |
wcspbrk | Ищет первое вхождение нескольких широких символов в строку широких символов. |
wcsspn | Определяет число широких символов в начальном сегменте строки широких символов. |
wcscspn | Ищет строку широких символов. |
wcswcs | Ищет первое вхождение строки широких символов в другую строку широких символов. |
wcstok | Разбивает строку широких символов на отдельные подстроки. |
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, wc, *pws; int retval; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** символом NULL, wc - указатель на искомый широкий символ. ** */ pws = wcschr(pwcs1, wc); if (pws == (wchar_t )NULL ){ /* в строке pwcs1 нет символа wc */ }else{ /* pws указывает на позицию, в которой найден символ wc */ } }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, wc, *pws; int retval; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** символом NULL, wc - указатель на искомый широкий символ. ** */ pws = wcsrchr(pwcs1, wc); if (pws == (wchar_t )NULL ){ /* в строке pwcs1 нет символа wc */ }else{ /* pws указывает на позицию, в которой найден символ wc */ } }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2, *pws; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** оканчивающуюся символом NULL, pwcs2 - указатель на строку ** искомых широких символов. */ pws = wcspbrk(pwcs1, pwcs2); if (pws == (wchar_t )NULL ){ /* В строке pwcs1 не обнаружено символов из строки pwcs2 */ }else{ /* pws указывает на позицию, в которой обнаружено совпадение */ } }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2; size_t count; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** оканчивающуюся символом NULL, pwcs2 - указатель на строку ** искомых широких символов. */ count = wcsspn(pwcs1, pwcs2); /* ** count содержит длину сегмента. */ }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2; size_t count; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** оканчивающуюся символом NULL, pwcs2 - указатель на строку ** искомых широких символов. */ count = wcscspn(pwcs1, pwcs2); /* ** count содержит длину сегмента, состоящего из символов, ** не входящих в строку pwcs2. */ }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1, *pwcs2, *pws; (void)setlocale(LC_ALL, ""); /* ** Пусть pwcs1 - это указатель на строку широких символов, оканчивающуюся ** оканчивающуюся символом NULL, pwcs2 - указатель на строку ** строку широких символов. */ pws = wcswcs(pwcs1, pwcs2); if (pws == (wchar_t)NULL){ /* В строке pwcs1 не обнаружено последовательности широких символов pwcs2 */ }else{ /* ** pws указывает на позицию первого вхождения ** последовательности pwcs2 в строку pwcs1. */ } }
#include <string.h> #include <locale.h> #include <stdlib.h> main() { wchar_t *pwcs1 = L"?a???b,,,#c"; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); pwcs = wcstok(pwcs1, L"?"); /* pws указывает на метку: L"a" */ pwcs = wcstok((wchar_t *)NULL, L","); /* pws указывает на метку: L"??b" */ pwcs = wcstok((wchar_t *)NULL, L"#,"); /* pws указывает на метку: L"c" */ }
В NLS поддерживаются функции как форматированного, так и неформатированного ввода-вывода.
К семейству функций printf и scanf добавлены функции, позволяющие форматировать широкие символы. Для обработки широких символов в функциях printf и scanf предусмотрены два дополнительных спецификатора формата: %C и %S. Они предназначены для ввода-вывода широкого символа и строки широких символов, соответственно. Эти спецификаторы формата подобны спецификаторам %c и %s, позволяющим выполнять ввод-вывод многобайтовых символов и строк.
Функции обработки многобайтовых символов принимают на входе массив многобайтовых символов и возвращают также массив многобайтовых символов. Для преобразования массива многобайтовых символов, возвращаемого такой функцией, в строку широких символов можно воспользоваться функцией mbstowcs.
Функции неформатированного ввода-вывода применяются в тех случаях, когда ввод-вывод многобайтовых символов в программе не должен зависеть от кодового набора. Например, для ввода многобайтового символа можно использовать функцию fgetwc или getwc. Если программа использует функцию getc для ввода многобайтовых символов, функция getc должна вызываться для ввода каждого байта многобайтового символа.
Функции ввода широких символов извлекают из потока многобайтовые символы и преобразуют их в широкие символы. Преобразование выполняется так же, как при вызове функций mbtowc и mbstowcs.
Функции вывода широких символов преобразуют широкие символы в многобайтовые и помещают результат в поток. Преобразование выполняется так же, как при вызове функций wctomb и wcstombs.
Работа функций ввода-вывода широких символов зависит от значения категории LC_CTYPE текущей локали.
Если программа должна обработать целый файл и преобразовать его в формат широких символов, то это можно сделать одним из следующих способов:
Какой из этих двух способов использовать, зависит от конкретной программы. Рекомендуется применять второй метод, поскольку он обеспечивает более высокую производительность и программе не нужно обрабатывать специальные случаи.
Для представления кода широкого символа, а также признака конца файла (EOF) требуется новый тип данных - wint_t. Рассмотрим, например, функцию fgetwc, возвращающую код широкого символа:
По этим причинам, значение, возвращаемое функцией fgetwc, должно быть представлено типом данных wint_t. Тип данных wint_t определен в файле wchar.h.
Для ввода широких символов
предназначены следующие функции:
fgetwc | Извлекает следующий широкий символ из потока. |
fgetws | Извлекает строку широких символов из потока. |
getwc | Извлекает следующий широкий символ из потока. |
getwchar | Считывает следующий широкий символ из стандартного файла ввода. |
getws | Считывает строку широких символов из стандартного файла ввода. |
ungetwc | Помещает широкий символ в поток. |
Для вывода широких символов
предназначены следующие функции:
fputwc | Помещает широкий символ в выходной поток. |
fputws | Помещает строку широких символов в выходной поток. |
putwc | Помещает широкий символ в выходной поток. |
putwchar | Отправляет широкий символ в стандартный файл вывода. |
putws | Отправляет строку широких символов в стандартный файл вывода. |
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { wint_t retval; FILE *fp; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); /* ** Открытие потока. */ fp = fopen("file", "r"); /* ** Если не удалось открыть поток, выполняется обработка ошибок. */ if(fp == NULL){ /* Обработка ошибок */ }else{ /* ** pwcs указывает на буфер широких символов с размером BUFSIZ. */ while((retval = fgetwc(fp)) != WEOF){ *pwcs++ = (wchar_t)retval; /* прерывание, если буфер заполнен */ } } /* Обработка широких символов в буфере */ }
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { wint_t retval; FILE *fp; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); index = 0; while((retval = getwchar()) != WEOF){ /* pwcs указывает на буфер широких символов с размером BUFSIZ. */ *pwcs++ = (wchar_t)retval; /* прерывание, если буфер заполнен */ } /* Обработка широких символов в буфере */ }
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { wint_t retval; FILE *fp; (void)setlocale(LC_ALL, ""); /* ** Открытие потока. */ fp = fopen("file", "r"); /* ** Если не удалось открыть поток, выполняется обработка ошибок. */ if(fp == NULL){ /* Обработка ошибок */ else{ retval = fgetwc(fp); if(retval != WEOF){ /* ** Считывание символа и возврат его в поток. */ retval = ungetwc(retval, fp); if(retval == EOF){ /* Ошибка в ungetwc */ } } } }
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { FILE *fp; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); /* ** Открытие потока. */ fp = fopen("file", "r"); /* ** Если не удалось открыть поток, выполняется обработка ошибок. */ if(fp == NULL){ /* Обработка ошибок */ }else{ /* pwcs указывает на буфер широких символов с размером BUFSIZ. */ while(fgetws(pwcs, BUFSIZ, fp) != (wchar_t *)NULL){ /* ** pwcs содержит широкие символы и ** конечный символ NULL. */ } } }
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { int index, len; wint_t retval; FILE *fp; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); /* ** Открытие потока. */ fp = fopen("file", "w"); /* ** Если не удалось открыть поток, выполняется обработка ошибок. */ if(fp == NULL){ /* Обработка ошибок */ }else{ /* Пусть len - число широких символов, помещаемых в выходной поток. ** pwcs указывает на буфер широких символов с размером BUFSIZ. */ for(index=0; index < len; index++){ retval = fputwc(*pwcs++, fp); if(retval == WEOF) break; /* произошла ошибка записи */ /* код ошибки содержится в errno. */ } } }
#include <stdio.h> #include <locale.h> #include <stdlib.h> main() { int retval; FILE *fp; wchar_t *pwcs; (void)setlocale(LC_ALL, ""); /* ** Открытие потока. */ fp = fopen("file", "w"); /* ** Если не удалось открыть поток, выполняется обработка ошибок. */ if(fp == NULL){ /* Обработка ошибок */ }else{ /* ** pwcs указывает на строку широких символов, ** которую следует записать в fp. */ retval = fputws(pwcs, fp); if(retval == -1){ /* Произошла ошибка записи */ /* код ошибки содержится в errno. */ } } }
Константа L может применяться только для символов ASCII. Для символов ASCII значение константы L равно кодовому знаку символа. Например, L'a' - это то же самое, что и a. Константа L применяется в том случае, если необходимо получить значение wchar_t символа ASCII. Спецификатор L задает т.н. константу широких символов. Например:
wchar_t wc = L'x' ;
Код широкого символа, соответствующий символу x, хранится в wc. Компилятор C преобразует символ x в широкий символ с помощью функции mbtowc или mbstowcs. Это преобразование выполняется в соответствии с параметрами локали, существующими на момент компиляции. Так как символы ASCII входят во все поддерживаемые кодовые наборы и во всех локалях представляются одними и теми же широкими символами, то L'x' во всех кодовых наборах имеет одно и то же значение. Однако, если x - не ASCII-символ, то программа не будет работать, если запустить ее с иным кодовым набором, нежели тот, что использовался при компиляции. Это ограничение относится к программам, использующим представление константы широких символов в операторах switch.
См. пример фрагмента программы, откомпилированной с кодовым набором IBM-850.
wchar_t wc; switch(wc){ case L'a-umlaut':/* здесь должна быть буква а с умляутом */ /* обработка */ break; case :L'c-cedilla':/* здесь должна быть буква с с седилем */ /* обработка */ break; default: break; }
Если эта программа компилируется и запускается в системе с кодовым набором IBM-850, она будет работать правильно. Однако, если запустить этот исполняемый файл в системе с кодировкой ISO8859-1, то произойдет сбой. В кодовых наборах IBM-850 и ISO8859-1 коды символов a-умляут и c-седиль различны.
Раздел Функции для поддержки национальных языков - Обзор - функции обработки широких и многобайтовых символов.
Раздел Глава 16, Поддержка национальных языков и Локаль - Информация для программистов - общие вопросы локализации программного обеспечения.
Описание категории 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.