[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]

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


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

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

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

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

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

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

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

Функции преобразования многобайтовых символов в широкие символы

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

mblen

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

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

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

Функции преобразования широких символов в многобайтовые символы

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

wcslen

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

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

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

Примеры

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

    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.
        */ 
    }
    
  2. В следующем примере для преобразования широкого символа в многобайтовый применяется функция wctomb:

    #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, в байтах.
        */
    }
    
  3. В следующем примере для определения длины многобайтового символа (в байтах) применяется функция mblen:

    #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){
            /* Обработка ошибок */
        }
    }
    
  4. В следующем примере определяется позиция предыдущего символа в строке многобайтовых символов. Если вам требуется определить позицию предыдущего символа, начиная с позиции текущего символа (а не с некоторой случайной позиции), то вам придется перебрать все символы в буфере, начиная с начала. Вызывайте функцию mblen, пока не достигнете позиции текущего символа, и сохраняйте позицию предыдущего символа.

    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 ), то это означает, что
    ** предыдущего символа нет. Кроме того, если все символы вплоть до
    ** текущего являются недопустимыми, все они будут рассматриваться как
    ** обычные однобайтовые символы, а это может быть совсем не то, что вам
    ** нужно. Такой порядок обработки можно изменить, выбрав другой
    ** способ исправления ошибок.
    
  5. В следующем примере для преобразования строки многобайтовых символов в строку широких символов применяется функция mbstowcs:

    #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 содержит строку широких символов.
              */
    }
    
  6. В следующем примере проиллюстрировано преобразование большого блока данных в широкий формат с помощью функции mbstowcs. Когда функция mbstowcs обнаруживает недопустимый многобайтовый символ, она возвращает значение -1, но не указывает, где произошла ошибка. Поэтому функцию mbtowc следует использовать в цикле, чтобы она преобразовывала по одному символу.

    Примечание: Такой способ обработки значительно замедляет выполнение программы.
    При преобразовании однобайтовых кодовых наборов нет возможности обрабатывать неполные многобайтовые символы. Однако при преобразовании многобайтовых кодовых наборов неполные многобайтовые символы копируются в буфер сохранения. При следующем вызове функции 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){          /* обработка ошибок */
                }
                /* Обработка буфера с широкими символами */
            }
        }
    }
    
  7. В следующем примере для преобразования строки широких символов в строку многобайтовых символов применяются функции wcstombs и wcslen:

    #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

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

Примеры

  1. В этом примере с помощью функции 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 обнаружен
            **  недопустимый или непечатаемый символ.
            */
        }
    }
    
  2. В этом примере с помощью функции wcswidth определяется длина строки широких символов на экране:

    #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

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

Примеры

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

    #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){
            /*  произошла ошибка... обработка ошибки ...*/
        }
    }
    
  2. В следующем примере для сравнения двух строк широких символов на основе весов символов применяется функция wcsxfrm:

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

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

Примеры

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

    #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 содержит искомое число двойной точности. */
    }
    
  2. В следующем примере для преобразования строки широких символов в длинное целое число со знаком применяется функция wcstol:

    #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 записано длинное целое число. */
    }
    
  3. В следующем примере для преобразования строки широких символов в длинное целое число без знака применяется функция wcstoul:

    #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

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

Примеры

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

    #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  */
        }
    }
    
  2. В следующем примере для поиска последнего вхождения широкого символа в строку широких символов применяется функция wcsrchr:

    #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  */
        }
    }
    
  3. В следующем примере для поиска первого вхождения нескольких широких символов в строку широких символов применяется функция wcspbrk:

    #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 указывает на позицию, в которой обнаружено совпадение */
        }
    }
    
  4. В следующем примере для определения числа широких символов в начальном сегменте строки широких символов применяется функция wcsspn:

    #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 содержит длину сегмента.
        */
     }
    
  5. В следующем примере для определения числа широких символов, не входящих в сегмент строки широких символов, применяется функция wcscspn:

    #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.
        */
    }
    
  6. В следующем примере для определения первого вхождения строки широких символов в другую строку широких символов применяется функция wcswcs:

    #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.
            */
        }
    }
    
  7. В следующем примере с помощью функции wcstok выполняется разметка строки широких символов:

    #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, возвращающую код широкого символа:


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 выполняется чтение широких символов из файла:

    #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;
                   /*  прерывание, если буфер заполнен  */
            }
        }
        /*  Обработка широких символов в буфере  */
    }
    
  2. В следующем примере с помощью функции getwchar выполняется чтение широких символов из стандартного файла ввода:

    #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;
            /*  прерывание, если буфер заполнен  */
        }
        /*  Обработка широких символов в буфере  */
    }
    
  3. В следующем примере с помощью функции ungetwc выполняется занесение широкого символа во входной поток:

    #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  */
                }
            }
        }
    }
    
  4. В следующем примере с помощью функции fgetws выполняется построчное чтение файла:

    #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.
                */
            }
        }
    }
    
  5. В следующем примере с помощью функции fputwc выполняется запись широких символов в выходной поток:

    #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. */
            }
        }
    }
    
  6. В следующем примере с помощью функции fputws выполняется запись строки широких символов в файл:

    #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.


[ Страница назад | Страница вперед | Содержание | Индекс | Библиотека | Юридическая информация | Поиск ]