— тогда, независимо от установленных в окружении других переменных
LC_xxx
, локали подчиняются лишь функции времени и даты. Все остальные действуют так, как если бы программа по-прежнему работала в локали «С». Сходным образом вызов:
setlocale(LC_TIME, "it_IT"); /* Время всегда итальянское */
заменяет переменную окружения
LC_TIME
(также, как
LC_ALL
), заставляя программу использовать для вычислений времени/даты данные для Италии. (Хотя Италия может быть прекрасным местом, программам лучше использовать
""
, чтобы они могли корректно работать
везде; этот пример предназначен лишь для объяснения того, как работает
setlocale
.)
Можно индивидуально вызывать
setlocale
для каждой категории, но простейшим способом является установка всего одним махом:
/* Находясь в Риме, вместо «всего» делайте все как римляне. :-) */
setlocale(LC_ALL, "");
Возвращаемое
setlocale
значение является текущей установкой локали. Это либо строковое значение, переданное в предыдущем вызове, либо непрозрачное значение, представляющее используемую вначале локаль. Это самое значение может быть затем передано обратно
setlocale
. Для последующего использования возвращаемое значение должно быть скопировано в локальное хранилище, поскольку это указатель на внутренние данные.
char *initial_locale;
initial_locale = strdup(setlocale(LC_ALL, "")); /* сохранить копию */
...
(void)setlocale(LC_ALL, initial_locale); /* восстановить ее */
Здесь мы сохранили копию, использовав функцию POSIX
strdup
(см. раздел 3.2.2 «Копирование строк:
strdup
»).
13.2.3. Сравнение строк:
strcoll
и
strxfrm
Знакомая функция
strcmp
сравнивает две строки, возвращая отрицательное, нулевое или положительное значения, если первая строка меньше, равна или больше второй. Это сравнение основано на числовых значениях символов в машинном наборе символов. Из-за этого результаты
strcmp
никогда не изменяются.
Однако, при наличии локалей простого числового сравнения недостаточно. Каждая локаль определяет для содержащихся в ней символов последовательность сортировки, другими словами, относительный порядок символов внутри локали. Например, в простом 7-битном ASCII у двух символов '
А
' и '
а
' десятичные значения равны 65 и 97 соответственно. Соответственно, во фрагменте
int i = strcmp("А", "a");
i
имеет отрицательное значение. Однако, в локали "
en_US.UTF-8
" '
A
' идет после '
a
', а не перед ним. Таким образом, использование
strcmp
для приложений, использующих локаль, является плохой мыслью, мы могли бы сказать, что она возвращает игнорирующий локаль ответ.
Функция
strcoll
(string collate — сортировка строк) существует для сравнения строк с использованием локали:
#include <string.h> /* ISO С */
int strcoll(const char *s1, const char *s2);
Она возвращает такие же отрицательные/нулевые/положительные значения, что и
strcmp
. Следующая программа,
ch13-compare.c
,
интерактивно демонстрирует разницу:
1 /* ch13-compare.с --- демонстрация strcmp против strcoll */
2
3 #include <stdio.h>
4 #include <locale.h>
5 #include <string.h>
6
7 int main(void)
8 {
9 #define STRBUFSIZE 1024
10 char locale[STRBUFSIZE], curloc[STRBUFSIZE];
11 char left[STRBUFSIZE], right[STRBUFSIZE];
12 char buf[BUFSIZ];
13 int count;
14
15 setlocale(LC_ALL, ""); /* установить локаль */
16 strcpy(curloc, setlocale(LC_ALL, NULL)); /* сохранить ее */
17
18 printf("--> "); fflush(stdout);
19 while (fgets(buf, sizeof buf, stdin) != NULL) {
30 printf("%s: strcmp(\"%s\", \"%s\") is %d\n", curloc, left,
31 right, strcmp(left, right));
32 printf("%s: strcoll(\"%s\", \"%s\") is %d\n", curloc, left,
33 right, strcoll(left, right));
34
35 printf("\n--> "); fflush(stdout);
36 }
37
38 exit(0);
39 }
Программа читает входные строки, состоящие из двух сравниваемых слов и необязательной локали, использующейся для сравнения. Если локаль дана, она становится локалью для последующих элементов. Программа начинает с любой локалью, которая установлена в окружении.
Массив
curloc
сохраняет текущую локаль для вывода результатов;
left
и
right
являются левым и правым сравниваемыми словами (строки 10–11). Основную часть программы составляет цикл (строки 19–36), который читает строки и выполняет работу. Строки 20–23 разделяют входную строку,
locale
инициализируется пустой строкой, если третья строка не предусмотрена.
Строки 25–28 устанавливают новую локаль, если она приведена. Строки 30–33 выводят результаты сравнения, а строка 35 приглашает для дальнейшего ввода. Вот демонстрация:
$ ch13-compare /* Запуск программы */
– -> ABC abc /* Ввести два слова */
С: strcmp("ABC", "abc") is -1 /* Программа началась в локали "С" */
С: strcoll("ABC", "abc") is -1 /* В локали "С" идентичные рез-ты */