Д. Стефенс - C++. Сборник рецептов
Большую часть времени вам не придется беспокоиться по поводу получения информации о форматировании, содержащейся в moneypunct. Однако если вам необходимо выполнить большой объем формирования денежных значений в различных локализациях, то имеет смысл поэкспериментировать и познакомиться с особенностями форматирования в различных локализациях.
Смотри такжеРецепты 13.2 и 13.3.
13.5. Сортировка локализованных строк
Имеется последовательность строк, содержащая символы не в коде ASCII, и требуется ее отсортировать с учетом местных особенностей.
РешениеВ класс локализации встроена поддержка операций сравнения символов в заданной локализации путем перегрузки оператора operator<. При вызове любой стандартной функции, принимающей функтор сравнения, можно использовать в качестве такого функтора экземпляр класса локализации. (См. пример 13.8.)
Пример 13.8. Сортировка с учетом местных особенностей
#include <iostream>
#include <locale>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool localelessThan(const string& s1, const string& s2) {
const collate<char>& col =
use_facet<collate<char> >(locale()); // Использовать глобальную
// локализацию
const char* pb1 = s1.data();
const char* pb2 = s2.data();
return (col.compare(pb1, pb1 + s1.size(),
pb2, pb2 + s2.size()) < 0);
}
int main() (
// Создать две строки, одна с немецким символом
string s1 = "diät";
string s2 = "dich";
vector<string> v;
v.push_back(s1);
v.push_back(s2);
// Сортировать, не используя заданную локализацию, т.е. Применяя
// правила текущей глобальной локализации
sort(v.begin(), v.end());
for (vector<string>::const_iterator p = v.begin();
p != v.end(); ++p)
cout << *p << endl;
// Установить в качестве глобальной немецкую локализацию и затем
// сортировать
locale::global(locale("german"));
sort(v.begin(), v.end(), localelessThan);
for (vector<string>::const_iterator p = v.begin();
p != v.end(); ++p)
cout << *p << endl;
}
Первый вариант обеспечивает сортировку по коду ASCII, и поэтому результат будет выглядеть следующим образом.
dich
diät
Вторая сортировка использует правильный порядок букв немецкого алфавита, и поэтому результат будет противоположным.
diät
dich
ОбсуждениеСортировка усложняется, когда вы работаете с различными локализациями, но стандартная библиотека решает эту проблему. Фасет collate обеспечивает функцию-член compare, которая работает как strcmp: она возвращает значение -1, если первая строка меньше второй, значение 0, если они равны, и значение 1, если первая строка больше второй. В отличие от strcmp, функция collate::compare использует определенную в целевой локализации упорядоченность символов.
В примере 13.8 приводится функция localeLessThan, которая возвращает True, если согласно глобальной локализации первый аргумент меньше второго. Самым важным здесь моментом является вызов функции сравнения.
col.compare(pb1, // Указатель на первый символ
pb1 + s1.size(), // Указатель на позицию за последним символом
pb2,
pb2 + s2.size());
Выполнение примера 13.8 на вашем компьютере может дать результат как совпадающий, так и не совпадающий с приведенным мною, — это зависит от используемого в вашей реализации набора символов. Однако, если требуется обеспечить сравнение строк с учетом местных особенностей, вам следует использовать collate::compare. Конечно, стандарт не требует, чтобы реализация поддерживала какую-либо локализацию, кроме локализации «C», поэтому не забудьте протестировать все используемые вами локализации.
Глава 14
XML
14.0. Введение
Язык XML играет важную роль во многих областях, в том числе при хранении и поиске информации, в издательском деле и при передаче данных по сетям; в данной главе мы научимся работать с XML в С++. Поскольку эта книга больше посвящена С++, чем XML, я полагаю, вы уже имеете некоторый опыт применения различных технологий, связанных с XML, например SAX, DOM, XML Schema, XPath и XSLT. He стоит беспокоиться из-за того, что вы не являетесь экспертом во всех этих областях; приводимые в данной главе рецепты достаточно независимы друг от друга, поэтому вы можете пропустить некоторые из них и все-таки понять остальные. Во всяком случае, каждый рецепт дает краткое описание концепций XML и используемого ими инструментария.
Если вы имеете достаточный опыт программирования на другом языке, например на Java, вы можете предположить, что средства обработки документов XML входят в состав стандартной библиотеки С++. К сожалению, XML делал только первые шаги, когда стандарт C++ был уже принят, и хотя добавление средств обработки документов XML в новую версию стандартной библиотеки C++ вызывает большой интерес, в настоящее время вам придется полагаться на несколько доступных в C++ великолепных библиотек XML, поставляемых независимыми разработчиками.
Возможно, перед началом чтения рецептов вы захотите скачать из Интернета и установить библиотеки, которые будут рассмотрены в настоящей главе. В табл. 14.1 приводятся домашние страницы каждой библиотеки, а в табл. 14.2 указано назначение каждой библиотеки и ссылки на рецепты, в которых они используются. В таблицах не указаны точные версии различных спецификаций и рекомендаций XML, реализованные каждой библиотекой, поскольку эта информация, вероятно, изменится в ближайшем будущем.
Табл. 14.1. Библиотеки C++ для XML
Имя библиотеки Домашняя страница TinyXml www.grinninglizard.com/tinyxml Xerxes xml.apache.crg/xerces-c Xalan xml.apache.org/xalan-c Pathan 1 software.decisionsoft.com/pathanIntro.html Boost.Serialization www.boost.org/libs/serializationТабл. 14.2. Назначение библиотек
Имя библиотеки Назначение Рецепты TinyXml DOM (нестандартная версия) Рецепт 14.1 Xerxes SAX2, DOM, XML Schema Рецепты 14.2-14.8 Xalan XSLT, XPath Рецепты 14.7-14.8 Pathan XPath Рецепт 14.8 Boost.Serialization Сериализация XML Рецепт 14.914.1. Синтаксический анализ простого документа XML
Имеется некоторая совокупность данных, хранимых в документе XML. Требуется выполнить синтаксический анализ документа и превратить эти данные в объекты C++. Документ XML имеет достаточно небольшой размер и может поместиться в оперативной памяти, причем в документе не используется внутреннее определение типа документа (Document Type Definition — DTD) и отсутствуют пространства имен XML.
РешениеИспользуйте библиотеку TinyXml. Во-первых, определите объект типа TiXmlDocument и вызовите его метод LoadFile(), передавая полное имя файла вашего XML-документа в качестве его аргумента. Если LoadFile() возвращает значение «true», то это означает, что анализ вашего документа завершился успешно. В этом случае вызовите метод RootElement() для получения указателя на объект типа TiXmlElement, представляющего корневой элемент документа. Этот объект имеет иерархическую структуру, которая соответствует структуре вашего документа XML; выполняя проход по этой структуре, вы можете извлечь информацию о документе и использовать ее для создания набора объектов С++.
Например, предположим, что у вас имеется XML-документ animals.xml, описывающий некоторое количество животных цирка, как показано в примере 14.1. Корень документа имеет имя animalList и содержит несколько дочерних элементов animal, каждый из которых представляет одно животное, принадлежащее цирку Feldman Family Circus. Предположим также, что у вас имеется класс C++ с именем Animal, и вам нужно сконструировать вектор std::vector, состоящий из объектов Animal, представляющих животных, перечисленных в документе.