equalсравнивает две последовательности на равенство. Имеется две версии: одна использует operator==, а другая использует переданный ей функциональный объект двоичного предиката (т.е. такой, который принимает два аргумента и возвращает bool). В примере 4.21 caseInsCharCompareNи W— это функции двоичного предиката.
Но это не всё, что требуется сделать; также требуется сравнить размеры. Рассмотрим объявление equal.
template
typename BinaryPredicate>
bool equal(InputIterator1 first, InputIterator1 last1,
InputIterator2 first2, BinaryPredicate pred);
Пусть n — это расстояние между first1и last1, или, другими словами, длина первого диапазона. equalвозвращает true, если первые nэлементов обеих последовательностей равны. Это означает, что если есть две последовательности, где первые nэлементов равны, но вторая содержит больше чем nэлементов, то equalвернет true. Чтобы избежать такой ошибки требуется проверять размер.
Эту логику не обязательно инкапсулировать в функцию. Ваш или клиентский код может просто вызвать алгоритм напрямую, но проще запомнить и написать такое:
if (caseInsCompare(s1, s2)) { // они равны, делаем что-нибудь
чем такое:
if ((s1.size() == s2.size()) &&
std::equal(s1.begin(), s1.end(s2.begin(), caseInsCharCompare)) {
// они равны, делаем что-нибудь
когда требуется выполнить сравнение строк без учета регистра.
4.14. Выполнение поиска строк без учета регистра
Проблема
Требуется найти в строке подстроку, не учитывая разницу в регистре.
Решение
Используйте стандартные алгоритмы transformи search, определенные в , а также свои собственные функции сравнения символов, аналогичные уже показанным. Пример 4.22 показывает, как это делается.
Пример 4.22. Поиск строк без учета регистра
#include
#include
#include
#include
#include
using namespace std;
inline bool caseInsCharCompSingle(char a. char b) {
return(toupper(a) == b);
}
string::const_iterator caseInsFind(string& s, const string& p) {
string tmp;
transform(p.begin( ), p.end(), // Преобразуем шаблон
back_inserter(tmp), // к верхнему регистру
toupper);
return(search(s.begin(), s.end(), // Возвращаем итератор.
tmp.begin(), tmp.end(), // возвращаемый из
caseInsCharCompSingle)); // search
}
int main() {
string s = "row, row, row, your boat";
string p = "YOUR";
string::const_iterator ir = caseInsFind(s, p);
if (it != s.end()) {
cout << "Нашли!\n;
}
}
Возвращая итератор, который указывает на элемент целевой строки, где начинается шаблонная строка, мы обеспечиваем совместимость с другими стандартными алгоритмами, так как большинство из них принимают в качестве аргумента итератор.
Обсуждение
Пример 4.22 демонстрирует обычный ход действий при работе со стандартными алгоритмами. Создайте функцию, которая выполняет работу, а затем подключите ее как объект функции к наиболее подходящему алгоритму. Здесь работу выполняет функция charInsCharCompSingle, но в отличие от примера 4.21 эта функция сравнения символов переводит к верхнему регистру только первый аргумент. Это сделано потому, что немного далее в caseInsFindя перед использованием строки шаблона в поиске преобразую ее к верхнему регистру полностью и тем самым избегаю многократного преобразования символов строки шаблона к верхнему регистру.
После того как функция сравнения будет готова, используйте для поиска стандартные алгоритмы transformи search. transformиспользуется для преобразования к верхнему регистру всего шаблона (но не целевой строки). После этого используйте для поиска места вхождения подстроки search совместно с функцией сравнения.
Помните, что стандартные алгоритмы работают с последовательностями , а не со строками. Это общие алгоритмы, которые в основном (но не только) работают со стандартными контейнерами, но не делают никаких предположений о содержимом этих контейнеров. Все стандартные алгоритмы требуют передачи им функции сравнения (а в случае их отсутствия используют операторы по умолчанию), которые тем или иным способом сравнивают два элемента и возвращают bool, указывающий, дало ли сравнение истину или ложь.
В примере 4.22 есть одна вещь, которая выглядит странно. Вы видите, что caseInsCompareвозвращает const_iterator, как в
string::const_iterator caseInsFind(const string& s,
const string& p)
Что, если требуется изменить элемент, на который указывает возвращенный итератор? Тому есть причина. Она состоит в том, что константный итератор используется потому, что строки, которые передаются в caseInsFind, также передаются как const, и, следовательно, невозможно получить не- constитератор на const-строку. Если требуется итератор, который можно использовать для изменения строки, удалите constиз параметров и измените объявление функции так, чтобы она возвращала string::iterator.
Читать дальше