Книга: Эффективное использование STL
Сравнение строк без учета регистра символов
Сравнение строк без учета регистра символов
Мэтт Остерн
Если вам когда-либо доводилось писать программы, в которых используются строки (а кому, спрашивается, не доводилось?), скорее всего, вы встречались с типичной ситуацией — две строки, различающиеся только регистром символов, должны были интерпретироваться как равные. В этих случаях требовалось, чтобы операции сравнения — проверка равенства, больше-меньше, выделение подстрок, сортировка — игнорировали регистр символов. Программисты очень часто спрашивают, как организовать подобные операции средствами стандартной библиотеки C++. На этот вопрос существует огромное количество ответов, многие из которых неверны.
Прежде всего необходимо избавиться от мысли о написании класса, сравнивающего строки без учета регистра. Да, с технической точки зрения это более или менее возможно. Тип std::string
стандартной библиотеки в действительности является синонимом для типа std::basic_string<char, std::char_trais<char>, std::allocator<char> >
. Операции сравнения определяются вторым параметром; передавая второй параметр с переопределенными операциями «равно» и «меньше», можно специализировать basic_string
таким образом, что операции <
и =
будут игнорировать регистр символов. Такое решение возможно, но игра не стоит свеч.
• Вы не сможете выполнять операции ввода-вывода или это потребует больших дополнительных хлопот. Классы ввода-вывода стандартной библиотеки (такие как std::basic_istream
и std::basic_ostream
) специализируются по двум начальным параметрам std::basic_string
(а std::ostream
всего лишь является синонимом для std::basic_ostream<char, char_traits<char> >
). Параметры характеристик (traits
) должны совпадать. Если вы используете строки типа std::basic_string<char, my_traits_class>
, то для вывода строк должен использоваться тип std::basic_ostream<char, my_traits_class>
. Стандартные потоки cin
и cout
для этой цели не подойдут.
• Игнорирование регистра символов является не свойством объекта, а лишь контекстом его использования. Вполне возможно, что в одном контексте строки должны интерпретироваться с учетом регистра, а в другом контексте регистр должен игнорироваться (например, при установке соответствующего режима пользователем).
• Решение не соответствует канонам. Класс char_traits
, как и все классы характеристик[5], прост, компактен и не содержит информации состояния. Как будет показано ниже, правильная реализация сравнений без учета регистра не отвечает ни одному из этих критериев.
• Этого вообще не достаточно. Даже если все функции basic_string
будут игнорировать регистр, это никак не отразится на использовании внешних обобщенных алгоритмов, таких как std::search
и std::find_end
. Кроме того, такое решение перестает работать, если по соображениям эффективности перейти от контейнера объектов basic_string
к таблице строк.
Более правильное решение, которое лучше соответствует архитектуре стандартной библиотеки, заключается в том, чтобы игнорировать регистр символов только в тех случаях, когда это действительно необходимо. Не стоит возиться с такими функциями контейнера string
, как string::find_first
или string::rfind
; они лишь дублируют функциональные возможности, уже поддерживаемые внешними обобщенными алгоритмами. С другой стороны, алгоритмы обладают достаточной гибкостью, что позволяет реализовать в них поддержку сравнений строк без учета регистра. Например, чтобы отсортировать коллекцию строк без учета регистра, достаточно передать алгоритму працильный объект функции сравнения:
std::sort(C.begin(), C.end().compare_without_case);
Написанию таких объектов и посвящена эта статья.
- Сравнение строк без учета регистра
- Регистрация ТСР
- Инструмент командной строки gbak
- Инструмент командной строки gfix
- Восстановление "безнадежных" баз данных. InterBase Surgeon
- Система безопасности InterBase
- Общие рекомендации по безопасности
- Как выделить строку, столбец и ячейки
- Надежность и безопасность
- Удобная операция объединения строк
- Безопасная работа с внешними таблицами
- Работа со строками