Настройка локали

При изменении регистра русских букв может возникнуть проблема. Чтобы ее избежать, необходимо правильно настроить локаль (совокупность локальных настроек системы).

Настройка локали в языке C

Для настройки локали используется функция setlocale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
char *setlocale(int category, const char *locale);

В первом параметре указывается категория в виде числа от 0 до 5 или соответствующий числу макрос:

  • 0LC_ALL — устанавливает локаль для всех категорий;
  • 1LC_COLLATE — для сравнения строк;
  • 2LC_CTYPE — для перевода символов в нижний или верхний регистр;
  • 3LC_MONETARY — для отображения денежных единиц;
  • 4LC_NUMERIC — для форматирования дробных чисел;
  • 5LC_TIME — для форматирования вывода даты и времени.

Во втором параметре задается название локали в виде строки, например: rus, russian или Russian_Russia. В этом случае будет задана кодировка, используемая в системе по умолчанию:

char *pLocale = std::setlocale(LC_ALL, "Russian_Russia");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}
else std::cout << "Не удалось настроить локаль" << std::endl;

Чтобы использовать другую кодировку нужно указать ее название после точки, например, ".1251" или "Russian_Russia.1251":

char *pLocale = std::setlocale(LC_ALL, "Russian_Russia.1251");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}
else std::cout << "Не удалось настроить локаль" << std::endl;

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

char *pLocale = std::setlocale(LC_ALL, "");
if (pLocale) {
   std::cout << pLocale << std::endl; // Russian_Russia.1251
}

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

char *pLocale = std::setlocale(LC_ALL, nullptr);
if (pLocale) {
   std::cout << pLocale << std::endl; // C
}

Для настройки локали можно также использовать функцию _wsetlocale(). Прототип функции:

#include <cwchar> /* или #include <wchar.h> */
wchar_t *_wsetlocale(int category, const wchar_t *locale);

Параметры аналогичны одноименным параметрам функции setlocale(), но во втором параметре указывается L-строка с названием локали и возвращается указатель на L-строку:

wchar_t *pLocale = _wsetlocale(LC_ALL, L"Russian_Russia.1251");
if (pLocale) {
   std::wcout << pLocale << std::endl; // Russian_Russia.1251
}

После настройки локали многие функции будут работать не так как раньше. Например, от настроек локали зависит вывод функции printf():

std::printf("%.2f\n", 2.5);            // 2.50
std::setlocale(LC_NUMERIC, "dutch");
std::printf("%.2f\n", 2.5);            // 2,50

Некоторые функции позволяют указать локаль в качестве параметра, например, функция _printf_l():

int _printf_l(const char *format, _locale_t locale, ...);

Во втором параметре функция принимает структуру _locale_t с настройками локали. Создать эту структуру позволяет функция _create_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
_locale_t _create_locale(int category, const char *locale);

Все параметры аналогичны одноименным параметрам функции setlocale(). Если структуру создать не удалось, то функция возвращает нулевой указатель.

Создать структуру _locale_t с настройками текущей локали позволяет функция _get_current_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
_locale_t _get_current_locale(void);

Когда структура больше не нужна, ее следует освободить с помощью функции _free_locale(). Прототип функции:

#include <clocale> /* или #include <locale.h> */
void _free_locale(_locale_t locale);

Пример настройки локали и вывода текущего названия локали приведен в листинге 7.1.

Листинг 7.1. Настройка локали

#include <iostream>
#include <clocale>

int main() {
   char *pLocale = std::setlocale(LC_ALL, NULL);
   if (pLocale) {
      std::cout << pLocale << std::endl; // C
   }
   std::printf("%.2f\n", 3.14);          // 3.14
   pLocale = std::setlocale(LC_NUMERIC, "dutch");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Dutch_Netherlands.1252
   }
   std::printf("%.2f\n", 3.14);          // 3,14
   pLocale = std::setlocale(LC_ALL, "Russian_Russia");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Russian_Russia.1251
   }
   pLocale = std::setlocale(LC_ALL, "Russian_Russia.866");
   if (pLocale) {
      std::cout << pLocale << std::endl; // Russian_Russia.866
   }

   _locale_t locale_c = _create_locale(LC_NUMERIC, "C");
   _printf_l("%.2f\n", locale_c, 3.14);  // 3.14
   _free_locale(locale_c);
   _locale_t locale_de = _create_locale(LC_NUMERIC, "dutch");
   _printf_l("%.2f\n", locale_de, 3.14); // 3,14
   _free_locale(locale_de);
   return 0;
}

Функция localeconv() позволяет получить информацию о способе форматирования вещественных чисел и денежных сумм для текущей локали. Прототип функции:

#include <clocale> /* или #include <locale.h> */
struct lconv *localeconv(void);

Функция возвращает указатель на структуру lconv. Пример вывода символа десятичного разделителя для локали Russian_Russia.1251:

std::setlocale(LC_ALL, "Russian_Russia.1251");
lconv *p = std::localeconv();
if (p) {
   std::cout << p->decimal_point << std::endl;
}

Объявление структуры lconv выглядит следующим образом:

struct lconv {
   char *decimal_point;     // Десятичный разделитель (",")
   char *thousands_sep;     // Разделитель тысяч (" ")
   char *grouping;          // Способ группировки значений
   char *int_curr_symbol;   // Название валюты ("RUR")
   char *currency_symbol;   // Символ валюты ("р.")
   char *mon_decimal_point; // Десятичный разделитель для 
                            // денежных сумм (",")
   char *mon_thousands_sep; // Разделитель тысяч для денежных
                            // сумм (" ")
   char *mon_grouping;   // Способ группировки для денежных сумм
   char *positive_sign;  // Положительный знак для денежных сумм
   char *negative_sign;  // Отрицательный знак для денежных сумм ("-")
   char int_frac_digits; // Количество цифр в дробной части для 
                         // денежных сумм в международном формате (2)
   char frac_digits;     // Количество цифр в дробной части для
                         // денежных сумм в национальном формате (2)
   char p_cs_precedes;   // 1 - если символ валюты перед значением
                         // 0 - если символ валюты после значения
   char p_sep_by_space;  // 1 - если символ валюты отделяется пробелом
                         // 0 - в противном случае
                         // p_cs_precedes и p_sep_by_space применяются
                         // для положительных значений
   char n_cs_precedes;   // 1 - если символ валюты перед значением
                         // 0 - если символ валюты после значения
   char n_sep_by_space;  // 1 - если символ валюты отделяется пробелом
                         // 0 - в противном случае
                         // n_cs_precedes и n_sep_by_space применяются
                         // для отрицательных значений
   char p_sign_posn;     // Позиция символа положительного значения
   char n_sign_posn;     // Позиция символа отрицательного значения
};

В VC++ доступны также следующие поля структуры lconv:

wchar_t *_W_decimal_point;
wchar_t *_W_thousands_sep;
wchar_t *_W_int_curr_symbol;
wchar_t *_W_currency_symbol;
wchar_t *_W_mon_decimal_point;
wchar_t *_W_mon_thousands_sep;
wchar_t *_W_positive_sign;
wchar_t *_W_negative_sign;

Настройка локали в языке C++

В языке C++ настройка локали производится с помощью класса locale. Для создания объекта наиболее часто используются следующие конструкторы:

#include <locale>
locale() throw();
explicit locale(const char *locname);
explicit locale(const string &locname);
locale(const locale &other) throw();
locale(const locale &base, const char *locname, category cat);
locale(const locale &base, const string &locname, category cat);

Первый конструктор создает копию текущей глобальной локали, если она была предварительно установлена с помощью статического метода global(), или классическую локаль (возвращаемую статическим методом classic()):

std::locale loc;
std::cout << loc.name() << std::endl; // C

В этом примере для получения названия локали мы воспользовались методом name(). Прототип метода:

string name() const;

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

std::locale loc1("C");
std::cout << loc1.name() << std::endl; // C
std::locale loc2(std::string("C"));
std::cout << loc2.name() << std::endl; // C

Если указанной локали нет, то генерируется исключение runtime_error. Пример обработки исключения:

std::locale loc;
try {
   loc = std::locale("Russian_Russia.1251");
   std::cout << loc.name() << std::endl;
} catch (std::runtime_error &e) {
   std::cout << "Error" << std::endl;
}
/*
В VC++:  Russian_Russia.1251
В MinGW: Error
*/
Обратите внимание

Четвертый конструктор создает копию объекта:

std::locale loc1("C");
std::locale loc2(loc1);
std::cout << loc2.name() << std::endl; // C

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

  • locale::all — устанавливает локаль для всех категорий;
  • locale::collate — для сравнения строк;
  • locale::ctype — для перевода символов в нижний или верхний регистр;
  • locale::monetary — для отображения денежных единиц;
  • locale::numeric — для форматирования дробных чисел;
  • locale::time — для форматирования вывода даты и времени;
  • locale::messages;
  • locale::none — флаги не установлены.

Пример создания объекта класса locale для всех категорий:

std::locale loc;
loc = std::locale(loc, "C", std::locale::all);
std::cout << loc.name() << std::endl; // C

Создать объект класса locale для классической локали C позволяет статический метод classic(). Прототип метода:

static const locale &classic();

Пример:

std::locale loc = std::locale::classic();
std::cout << loc.name() << std::endl; // C

Чтобы установить локаль на глобальном уровне следует передать созданный объект в статический метод global(). Метод принимает объект класса locale и возвращает прежнюю настройку локали. Прототип метода global():

static locale global(const locale &loc);

Пример:

std::locale loc("C");
std::locale::global(loc);

В классе locale выполнена перегрузка операторов =, == и !=. Прототипы методов:

const locale &operator=(const locale &other) throw();
bool operator==(const locale &other) const throw();
bool operator!=(const locale &other) const throw();

Пример сравнения локалей:

if (std::locale() == std::locale::classic()) {
   std::cout << "C" << std::endl;
}

Учебник C++ (Qt Creator и MinGW)
Учебник C++ (Qt Creator и MinGW) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов