13.5. Сортировка локализованных строк

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», поэтому не забудьте протестировать все используемые вами локализации.