Один из вопросов, часто задаваемых новичками в STL — «Как в STL сравниваются строки без учета регистра символов?» Простота этого вопроса обманчива. Сравнения строк без учета регистра символов могут быть очень простыми или очень сложными в зависимости от того, насколько общим должно быть ваше решение. Если игнорировать проблемы интернационализации и ограничиться строками, на которые была рассчитана функция strcmp
, задача проста. Если решение должно работать со строками в языках, не поддерживаемых strcmp
(то есть практически в любом языке, кроме английского), или программа должна использовать нестандартный локальный контекст, задача чрезвычайно сложна.
В этом совете рассматривается простой вариант, поскольку он достаточно наглядно демонстрирует роль STL в решении задачи (более сложный вариант связан не столько с STL, сколько с проблемами локального контекста, упоминаемыми в приложении A). Чтобы простая задача стала интереснее, мы рассмотрим два возможных решения. Программисты, разрабатывающие интерфейсы сравнения строк без учета регистра, часто определяют два разных интерфейса: первый по аналогии с strcmp
возвращает отрицательное число, ноль или положительное число, а второй по аналогии с оператором <
возвращает true
или false
. Мы рассмотрим способы реализации обоих интерфейсов вызова с применением алгоритмов STL.
Но сначала необходимо определить способ сравнения двух символов без учета регистра. Если принять во внимание аспекты интернационализации, задача не из простых. Следующая функция сравнения несколько упрощена, но в данном совете проблемы интернационализации игнорируются, и эта функция вполне подойдет:
int ciCharCompare(char c1, char c2) // Сравнение символов без учета {
{ // регистра. Функция возвращает -1,
// если c1 < c2, 0, если c1 = c2, и 1,
// если c1 > c2.
int lc1 = tolower(static_cast
int lс2 = tolower(static_cast
if (lc1 < lc2) return -1;
if (lc1 > lc2) return 1;
return 0;
};
Функция ciCharCompare
по примеру strcmp
возвращает отрицательное число, ноль или положительное число в зависимости от отношения между c1
и c2
. В отличие от strcmp, функция ciCharCompare
перед сравнением преобразует оба параметра к нижнему регистру. Именно так и достигается игнорирование регистра символов при сравнении.
Параметр и возвращаемое значение функции tolower
, как и у многих функций
, относятся к типу int
, но эти числа (кроме EOF
) должны представляться в виде unsigned char
. В C и C++ тип char
может быть как знаковым, так и беззнаковым (в зависимости от реализации). Если тип char
является знаковым, гарантировать его возможное представление в виде unsigned char
можно лишь одним способом: преобразованием типа перед вызовом tolower
, этим и объясняется присутствие преобразований в приведенном выше фрагменте (в реализациях с беззнаковым типом char
преобразование игнорируется). Кроме того, это объясняет сохранение возвращаемого значения tolower
в переменной типа int
вместо char
.
При наличии chCharCompare
первая из двух функций сравнения строк (с интерфейсом в стиле strcmp
) пишется просто. Эта функция, ciStringCompare
, возвращает отрицательное число, ноль или положительное число в зависимости от отношения между сравниваемыми строками. Функция основана на алгоритме mismatch
, определяющем первую позицию в двух интервалах, в которой элементы не совпадают.
Но для вызова mismatch
должны выполняться некоторые условия. В частности, необходимо проследить за тем, чтобы более короткая строка (в случае строк разной длины) передавалась в первом интервале. Вся настоящая работа выполняется функцией ciStringCompareImpl
, а функция ciStringCompare
лишь проверяет правильность порядка аргументов и меняет знак возвращаемого значения, если аргументы пришлось переставлять:
int ciStringCompareImpl(const string& si, // Реализация приведена далее
const string& s2);
int ciStringCompare(const string& s1, const string& s2) {
if (s1.size<=s2.size return cStringCompareImpl(s1, s2);
else return -ciStringComparelmpl(s2, s1);
}
Внутри ciStringCompareImpl
всю тяжелую работу выполняет алгоритм mismatch
. Он возвращает пару итераторов, обозначающих позиции первых отличающихся символов в интервалах: