Книга: Эффективное использование STL
Первая попытка
Первая попытка
Существует несколько способов упорядочения слов по алфавиту. Зайдите в книжный магазин и посмотрите, как расставлены книги на полках. Предшествует ли имя
1. См. статью Александреску А. (Andrei Alexandrescu) в майском номере «C++ Report» за 2000 г. [19].
Mary McCarthy имени Bernard Malamud или следует после него? (В действительности это лишь вопрос привычки, я встречал оба варианта.) Впрочем, простейший способ сравнения строк хорошо знаком нам по школе: речь идет о лексикографическом, или «словарном», сравнении, основанном на последовательном сравнений отдельных символов двух строк.
Лексикографический критерий сравнения может оказаться неподходящим для некоторых специфических ситуаций. Более того, единого критерия вообще не существует — например, имена людей и географические названия иногда сортируются по разным критериям. С другой стороны, в большинстве случаев лексикографический критерий подходит, поэтому он был заложен в основу механизма строковых сравнений в C++. Строка представляет собой последовательность символов. Если объекты x
и y
относятся к типу std::string
, то выражение x<y
эквивалентно выражению
std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end())
В приведенном выражении алгоритм lexicographical_compare
сравнивает отдельные символы оператором <
, однако существует другая версия lexicographical_compare
, позволяющая задать пользовательский критерий сравнения символов. Она вызывается с пятью аргументами вместо четырех; в последнем аргументе передается объект функции, двоичный предикат, определяющий, какой из двух символов предшествует другому. Таким образом, для сравнения строк без учета регистра на базе lexicographical_compare
достаточно объединить этот алгоритм с объектом функции, игнорирующим различия в регистре символов.
Распространенный принцип сравнения двух символов без учета регистра заключается в том, чтобы преобразовать оба символа к верхнему регистру и сравнить результаты. Ниже приведена тривиальная формулировка этой идеи в виде объекта функции C++ с использованием хорошо известной функции toupper из стандартной библиотеки C:
struct lt_nocase:
public std::binary_function<char, char, bool> {
bool operator()(char x, char y) const {
return std::toupper(static_cast<unsigned char>(x))<
std::toupper(static_cast<unsigned char>(y));
}
};
«У каждой сложной задачи есть решение простое, элегантное и… неправильное». Авторы книг C++ обожают этот класс за простоту и наглядность. Я тоже неоднократно использовал его в своих книгах. Он почти правилен, и все-таки не совсем, хотя недостаток весьма нетривиален. Следующий пример выявляет этот недостаток:
int main() {
const char* s1 = "GEW334RZTRAMINER";
const char* s2 = "gew374rztraminer";
printf("s1=%s, s2=%sn", s1, s2);
printf("s1<s2:%sn",
std::lexicographical_compare(s1, s1+14, s2, s2+14, lt_nocase())
?"true":"false");
}
Попробуйте запустить эту программу в своей системе. На моем компьютере (Silicon Graphics О2 с системой IRIX 6.5) результат выглядел так:
s1=GEW?RZTRAMINER,s2=gew?rztraminer
s1<s2:true
Странно… Разве при сравнении без учета регистра «GEW?RZTRAMINER» и «gew?rztraminer» не должны быть равными? И еще возможен вариант с небольшой модификацией: если перед командой printf вставить строку
setlocale(LC_ALL, "de");
результат неожиданно изменяется:
s1=GEW?RZTRAMINER,s2=gew?rztraminer
s1<s2:false
Задача сравнения строк без учета регистра сложнее, чем кажется сначала. Работа элементарной на первый взгляд программы в огромной степени зависит от того, о чем многие из нас предпочли бы забыть. Речь идет о локальном контексте.
- Часть первая Наука о скрытых мотивах поведения
- 2. Первая нормальная форма (1NF)
- Часть первая Открытие
- Ваша первая программа на Bash
- ПЕРВАЯ СТРАНИЦА
- Первая часть Что такое экспоненциальная организация?
- Конфигурация sendmail для противодействия попыткам передачи спама
- Первая задача: создать новую базу данных.
- 68. Дорога. Попытка фантазийного рассказа
- История Вселенной, часть первая
- Глава первая. Принцип отложенного вознаграждения
- Глава первая. Погружение в убедительность