Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

Заголовочный файл

<locale>
имеет три основные части. Во-первых, это класс
locale
(локализация). Он инкапсулирует все поддерживаемые в C++ особенности локализованного поведения и обеспечивает точки входа для получения различной информации о локализации, необходимой для выполнения локализованного форматирования. Во-вторых, самыми маленькими элементами локализации и конкретными классами, с которыми вы будете работать, являются классы, называемые фасетами (facets). Примером фасета является, например, класс
time_put
, предназначенный для записи даты в поток. В-третьих, каждый фасет принадлежит к некоторой категории, которая объединяет связанные фасеты в одну группу. Например, имеются числовая, временная и
денежная категории (только что упомянутый мною фасет
time_put
относится к временной категории). Я кратко описываю категории в данной главе, однако действительную пользу они приносят при осуществлении более изощренных действий, связанных с локализацией.

Каждая программа на C++ имеет, по крайней мере, одну локализацию, называемую глобальной локализацией (она часто реализуется как глобальный статический объект). По умолчанию это будет классическая локализация «С», пока вы не измените ее на что- нибудь другое. Один из конструкторов

locale
позволяет инстанцировать локализацию, предпочитаемую пользователем, хотя точное определение «предпочитаемой» пользователем локализации полностью зависит от реализации.

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

13.1. Жесткое кодирование строк в коде Unicode

Проблема

Требуется в исходном файле жестко закодировать строки в коде Unicode, т.е. используя расширенный набор символов.

Решение

Начинайте строку с префикса

L
и затем вводите символы в своем редакторе исходных текстов, как вы это обычно делаете при написании строк, или используйте шестнадцатеричные значения, представляющие нужный вам символ в коде Unicode. Пример 13.1 демонстрирует оба способа кодирования таких строк.

Пример 13.1. Жесткое кодирование строк в коде Unicode

#include <iostream>

#include <fstream>

#include <string>

using namespace std;

int main {

 // Создать несколько строк с символами кода Unicode

 wstring ws1 = L"Infinity: \u221E";

 wstring ws2 = L"Euro: €"

 wchar_t w[] = L"Infinity: \u221E";

 wofstream out("tmp\\unicode.txt");

 out << ws2 << endl;

 wcout << ws2 << endl;

}

Обсуждение

Основной вопрос, возникающий при жестком кодировании строк в коде Unicode, связан с выбором способа ввода строки в редакторе исходных текстов. В C++ предусмотрен тип расширенного набора символов

wchar_t
, который может хранить строки в коде Unicode. Точное представление
wchar_t
зависит от реализации, однако часто используется формат UTF-32. Класс
wstring
определяется в
<string>
как последовательность символов типа
wchar_t
, подобно тому как класс
string
представляет собой последовательность символов типа
char
. (Строго говоря, тип
wstring
определяется, конечно, с помощью
typedef
как
basic_string<wchar_t>
.)

Самый простой способ ввода символов в коде Unicode — это использование префикса

L
перед строковым литералом, как показано в примере 13.1.

wstring ws1 = L"Infinity, \u2210"; // Использовать сам код

wstring ws2 = L"Euro: €"; // или просто ввести символ

Теперь можно записать эти строки с расширенным набором символов в поток с расширенным набором символов.

wcout << ws1 << endl; // wcout -
версия cout для расширенного набора символов

Их можно записывать также в файлы:

wofstream out("tmp\\unicode.txt");

out << ws2 << endl;

При работе с различными кодировками наибольшую ловкость приходится проявлять не для ввода правильных символов в ваши исходные файлы, а при определении типа символьных данных, получаемых из базы данных, по запросу HTTP, из пользовательского ввода и т.д., что выходит за рамки стандарта C++. Стандарт C++ не устанавливает никаких специальных требований, кроме того, что операционная система может использовать для исходных файлов любую кодировку, если она поддерживает, по крайней мере, 96 символов, используемых в языке С++. Для символов, не попадающих в этот набор, называемый основным исходным набором символов, стандартом предусматривается возможность их получения с помощью escape-последовательностей

\uXXXX
или
\UXXXXXXXX
, где
X
— шестнадцатеричная цифра.

13.2. Запись и чтение чисел

Проблема

Требуется записать число в поток в форматированном виде в соответствии с местными соглашениями.

Решение

Закрепите (imbue) текущую локализацию за потоком, в который вы собираетесь писать данные, и запишите в него числа, как это сделано в примере 13.2, или можете установить глобальную локализацию и затем создать поток. Последний подход рассматривается в обсуждении.

Пример 13.2. Запись чисел с использованием локализованного форматирования

#include <iostream>

#include <locale>

#include <string>

using namespace std;

// На заднем плане существует глобальная локализация, установленная средой

// этапа выполнения. По умолчанию это локализация "С". Вы можете ее

// заменить локализацией locale::global(const locale&).

int main {

 locale loc(""); // Создать копию пользовательской локализации

 cout << "Locale name = " << loc.name << endl;

 cout.imbue(loc); // Уведомить cout о необходимости применения

// пользовательской локализации при форматировании

 cout << "pi in locale " << cout.getloc.name << " is << 3.14 << endl;

}

Обсуждение

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

locale
, который затем закрепляется за потоком с помощью функции
imbue
.

Сначала в примере 13.2 создается

loc
, который является копией пользовательской локализации. Это необходимо делать, используя конструктор
locale
, принимающий пустую строку (а не конструктор по умолчанию).

locale loc("");

Отличие небольшое, но важное, и я вскоре вернусь к нему. При создании здесь объекта

locale
создается копия «пользовательской локализации», которая зависит от реализации. Это значит, что, если машина сконфигурирована на применение американского варианта английского языка, функция
locale::name
может возвращать такие строковые имена локализации, как «
en_US
», «
English_United States.1252
», «
english-american
» и т.д. Реальная строка определяется реализацией, а по стандарту C++ достаточно иметь только одну локализацию — «C»-локализацию.

Поделиться с друзьями: