Case Insensitive Std::String.Find()

Case insensitive std::string.find()

You could use std::search with a custom predicate.

#include <locale>
#include <iostream>
#include <algorithm>
using namespace std;

// templated version of my_equal so it could work with both char and wchar_t
template<typename charT>
struct my_equal {
my_equal( const std::locale& loc ) : loc_(loc) {}
bool operator()(charT ch1, charT ch2) {
return std::toupper(ch1, loc_) == std::toupper(ch2, loc_);
}
private:
const std::locale& loc_;
};

// find substring (case insensitive)
template<typename T>
int ci_find_substr( const T& str1, const T& str2, const std::locale& loc = std::locale() )
{
typename T::const_iterator it = std::search( str1.begin(), str1.end(),
str2.begin(), str2.end(), my_equal<typename T::value_type>(loc) );
if ( it != str1.end() ) return it - str1.begin();
else return -1; // not found
}

int main(int arc, char *argv[])
{
// string test
std::string str1 = "FIRST HELLO";
std::string str2 = "hello";
int f1 = ci_find_substr( str1, str2 );

// wstring test
std::wstring wstr1 = L"ОПЯТЬ ПРИВЕТ";
std::wstring wstr2 = L"привет";
int f2 = ci_find_substr( wstr1, wstr2 );

return 0;
}

Case insensitive string::find

You could upper-case both strings and use the regular find. (Note: this approach may not be correct if you have Unicode string.)

In Boost there's also ifind_first for case-insensitive search. (note that it returns a range instead of a size_t).

#include <string>
#include <boost/algorithm/string/find.hpp>
#include <cstdio>
#include <cctype>

std::string upperCase(std::string input) {
for (std::string::iterator it = input.begin(); it != input.end(); ++ it)
*it = toupper(*it);
return input;
}

int main () {
std::string foo = "1 FoO 2 foo";
std::string target = "foo";

printf("string.find: %zu\n", foo.find(target));

printf("string.find w/ upperCase: %zu\n", upperCase(foo).find(upperCase(target)));

printf("ifind_first: %zu\n", boost::algorithm::ifind_first(foo, target).begin() - foo.begin());

return 0;
}

std::find case insensitive checking

You could probably do with std::equal and std::tolower to check both wstrings

#include <iostream>
#include <string>
#include <algorithm>
#include <cwctype>
#include <locale>

int main()
{
std::wstring wstr1 = L"dll", wstr2 = L"DLL";

auto icompare = [](wchar_t const &c1, wchar_t const &c2)
{
return std::tolower(c1, std::locale()) == std::tolower(c2, std::locale());
};

if (std::equal(wstr1.begin(), wstr1.end(), wstr2.begin(), wstr2.end(), icompare))
std::cout << "equal" << std::endl;
else
std::cout << "notEqual" << std::endl;

return 0;
}

For example: https://ideone.com/I3zukI

Case insensitive find on std::set

The equality operation is only used when the hashes compare equal. If the hashes don't compare equal, then the two strings won't be checked for exact equality. Otherwise, we'd just have to check every hash bucket - who cares if the hashes match or not? That would defeat the constant look up time of the hashed set.

You'll need to make a custom hash function that ignores case.

Given a hash set S, its hash function H(x), its equality operation x == y, and the hash equality H(x) == H(y): For all x and y that are valid elements of S, if x == y, then it must also be true that H(x) == H(y), otherwise S is said to be "totally jank".

Case insensitive find() method in string class

If you can't modify the string, make a copy of it. Convert all chars to lowercase in the string and then use find() with a lowercase string.

Case-insensitive string comparison in C++

Boost includes a handy algorithm for this:

#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>

std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";

if (boost::iequals(str1, str2))
{
// Strings are identical
}

Case insensitive standard string comparison in C++

You can create a predicate function and use it in std::equals to perform the comparison:

bool icompare_pred(unsigned char a, unsigned char b)
{
return std::tolower(a) == std::tolower(b);
}

bool icompare(std::string const& a, std::string const& b)
{
if (a.length()==b.length()) {
return std::equal(b.begin(), b.end(),
a.begin(), icompare_pred);
}
else {
return false;
}
}

Now you can simply do:

if (icompare(str1, str)) {
std::cout << "Compares" << std::endl;
}


Related Topics



Leave a reply



Submit