Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 13:

Языково-культурная среда

Может показаться, что в деле интернационализации/локализации категориям LC_MONETARY и LC_NUMERIC повезло больше других, поскольку для них определена многокомпонентная структура lconv, содержащая значения всех ключевых слов этих категорий, и функция localeconv(), позволяющая данную структуру получить. Однако на практике дело обстоит прямо противоположным образом. Для других категорий настройка приложений на местную языково-культурную среду сводится к вызову

setlocale (LC_ALL, "");

Всю остальную специфику среды учитывают функции isalpha(), tolower(), strcoll(), strftime() и т.д., которыми приложения могут пользоваться стандартными способами.

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

#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>
#include <monetary.h>

#define MY_VALUE 1234.567

int main (void) {
	char sbuf [LINE_MAX];
	printf ("Текущая языково-культурная среда:
		подразумеваемая\n");
	printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
	printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
	printf ("Результат преобразования в денежную
		величину числа 1234.567\n");
	if (strfmon (sbuf, sizeof (sbuf), "Международное
		обозначение: %i\n", MY_VALUE) == -1) {
		perror ("STRFMON");
		return (1);
	}
	fputs (sbuf, stdout);
	(void) strfmon (sbuf, sizeof (sbuf), "Местное
		обозначение: %n\n", MY_VALUE);
	fputs (sbuf, stdout);
	(void) setlocale (LC_ALL, "");
	printf ("Текущая языково-культурная среда: местная\n");
	printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
	printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
	printf ("Результат преобразования в денежную
		величину числа 1234.567\n");
	(void) strfmon (sbuf, sizeof (sbuf),
		"Международное обозначение: %i\n", MY_VALUE);
	fputs (sbuf, stdout);
	(void) strfmon (sbuf, sizeof (sbuf), "Местное
		обозначение: %n\n", MY_VALUE);
	fputs (sbuf, stdout);
	(void) setlocale (LC_MONETARY, "ru_UA");
	printf ("Категория LC_MONETARY переустановлена
		для Украины\n");
	printf ("Результат преобразования в денежную
		величину числа 1234.567\n");
	(void) strfmon (sbuf, sizeof (sbuf),
		"Международное обозначение: %i\n", MY_VALUE);
	fputs (sbuf, stdout);
	(void) strfmon (sbuf, sizeof (sbuf), "Местное
		обозначение: %n\n", MY_VALUE);
	fputs (sbuf, stdout);
	return 0;
}
13.14. Пример программы, работающей в нескольких языково-культурных средах.

Текущая языково-культурная среда: подразумеваемая

isalpha ('Б'): 0
tolower ('Б'): 'Б'
Результат преобразования в денежную величину 
числа 1234.567
Международное обозначение: 1234.57
Местное обозначение: 1234.57
Текущая языково-культурная среда: местная
isalpha ('Б'): 1024
tolower ('Б'): 'б'
Результат преобразования в денежную величину 
числа 1234.567
Международное обозначение: 1 234.57 RUR
Местное обозначение: 1 234.57 руб
Категория LC_MONETARY переустановлена для 
Украины
Результат преобразования в денежную величину 
числа 1234.567
Международное обозначение: 1 234.57 UAH
Местное обозначение: 1 234.57 ГР
13.15. Текущая языково-культурная среда: подразумеваемая

Если требуется получить детальную информацию обо всех аспектах языково-культурной среды, можно воспользоваться функцией nl_langinfo() (см. листинг 13.16), отнесенной стандартом POSIX-2001 к расширению XSI.

#include <langinfo.h>
char *nl_langinfo (nl_item item);
13.16. Описание функции nl_langinfo().

Аргументом функции nl_langinfo() могут служить именованные константы, определенные в заголовочном файле <langinfo.h>. В общем и целом они соответствуют описанным выше ключевым словам. В качестве результата nl_langinfo() возвращает указатель на цепочку символов, содержащую данные о выбранном элементе среды. Если в текущей среде этот элемент отсутствует, выдаются данные для POSIX-среды.

Пример программы, использующей функцию nl_langinfo(), показан в листинге 13.17, возможные результаты ее работы – в листинге 13.18.

#include <stdio.h>
#include <locale.h>
#include <langinfo.h>
#include <regex.h>
#include <limits.h>

int main (void) {
	regex_t cere; /* Скомпилированные расширенные */
	/* регулярные выражения */
	regex_t ceren;
	int reerrcode; /* Код ошибки от regcomp или */
	/* regexec */
	char reerrbuf [LINE_MAX]; /* Буфер для строк с */
	/* сообщениями об ошибках */
	char response [LINE_MAX]; /* Буфер для ответа */

	/* пользователя */
	printf ("Текущая языково-культурная среда:
		подразумеваемая\n");
	printf ("Элемент YESEXPR категории LC_MESSAGES:
		%s\n", nl_langinfo (YESEXPR));
	printf ("Элемент MON_1 категории LC_TIME: %s\n",
		nl_langinfo (MON_1));
	(void) setlocale (LC_ALL, "");
	printf ("Текущая языково-культурная среда:
		местная\n");
	printf ("Элемент YESEXPR категории LC_MESSAGES:
		%s\n", nl_langinfo (YESEXPR));
	printf ("Элемент MON_1 категории LC_TIME: %s\n",
		nl_langinfo (MON_1));
	/* Скомпилируем расширенное регулярное */
	/* выражение для утвердительного ответа */
	if ((reerrcode = regcomp (&cere, nl_langinfo
		(YESEXPR), REG_EXTENDED | REG_ICASE |
		REG_NOSUB )) != 0) {
		(void) regerror (reerrcode, &cere, reerrbuf,
		sizeof (reerrbuf));
		fputs (reerrbuf, stderr);
		fputc ('\n', stderr);
		regfree (&cere);
		return (reerrcode);
	}
	/* То же для отрицательного ответа */
	if ((reerrcode = regcomp (&ceren, nl_langinfo
		(NOEXPR), REG_EXTENDED | REG_ICASE |
		REG_NOSUB )) != 0) {
		(void) regerror (reerrcode, &ceren, reerrbuf,
		sizeof (reerrbuf));
		fputs (reerrbuf, stderr);
		fputc ('\n', stderr);
		regfree (&ceren);
		return (reerrcode);
	}
	fputs ("Вы поддерживаете идею стандартизации
		программных интерфейсов? ", stdout);
	fgets (response, sizeof (response), stdin);
	if (regexec (&cere, response, 0, NULL, 0) == 0) {
		fputs ("Ответ положительный\n", stdout);
		} else if (regexec (&ceren, response, 0, NULL, 0) == 0) {
			fputs ("Ответ отрицательный\n", stdout);
	} else {
		fputs ("Ответ уклончивый\n", stdout);
	}
	regfree (&cere);
	regfree (&ceren);
	return 0;
}
13.17. Пример программы, использующей функцию nl_langinfo().
Текущая языково-культурная среда: подразумеваемая
Элемент YESEXPR категории LC_MESSAGES: ^[yY]
Элемент MON_1 категории LC_TIME: January
Текущая языково-культурная среда: местная
Элемент YESEXPR категории LC_MESSAGES: ^[ДдYy].*
Элемент MON_1 категории LC_TIME: Января
Вы поддерживаете идею стандартизации программных интерфейсов? Да
Ответ положительный
13.18. Возможные результаты работы программы, использующей функцию nl_langinfo().

К сожалению, обязательная часть стандарта POSIX-2001 содержит лишь минимум средств для настройки на целевую среду выдаваемых диагностических сообщений. По сути он сводится к функции strerror() (см. листинг 13.19), которая отображает номера (коды) ошибок в сообщения, зависящие от языково-культурной среды, точнее, от установки категории LC_MESSAGES.

#include <string.h>
char *strerror (int errnum);
13.19. Описание функции strerror().

Обычно в качестве аргумента этой функции используют errno, но номера ошибок могут поступать и из произвольного источника.

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

#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <errno.h>

int main (void) {
	fprintf (stderr, "Текущая языково-культурная
		среда: подразумеваемая\n");
	errno = 1;
	perror ("PERROR, сообщение номер 1");
	fprintf (stderr, "STRERROR, сообщение номер 1:
		%s\n", strerror (1));
	(void) setlocale (LC_ALL, "");
	fprintf (stderr, "Текущая языково-культурная
		среда: местная\n");
	errno = 1;
	perror ("PERROR, сообщение номер 1");
	fprintf (stderr, "STRERROR, сообщение номер 1:
		%s\n", strerror (1));
	(void) setlocale (LC_MESSAGES, "ru_UA");
	fprintf (stderr, "Категория LC_MESSAGES
		переустановлена для Украины\n");
	errno = 1;
	perror ("PERROR, сообщение номер 1");
	fprintf (stderr, "STRERROR, сообщение номер 1:
		%s\n", strerror (1));
return 0;
}
13.20. Пример программы, выдающей диагностические сообщения в разных языково-культурных средах и разными средствами.
Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?