Case insensitive std :: string.find ()

I use the std::string find() method to check if a string is a substring of another. Now I need a case-insensitive version of the same. For string comparisons, I can always refer to stricmp() , but stristr() does not seem to exist.

I found several answers, and most of them suggest using Boost , which is not an option in my case. In addition, I need to support std::wstring / wchar_t . Any ideas?

+43
c ++ string case-insensitive stl wstring
Jun 30 '10 at 18:28
source share
8 answers

You can use std::search with a special 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; } 
+60
Jun 30 '10 at 18:35
source share

New C ++ 11 style:

 #include <algorithm> #include <string> #include <cctype> /// Try to find in the Haystack the Needle - ignore case bool findStringIC(const std::string & strHaystack, const std::string & strNeedle) { auto it = std::search( strHaystack.begin(), strHaystack.end(), strNeedle.begin(), strNeedle.end(), [](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); } ); return (it != strHaystack.end() ); } 

The explanation "search" can be found at cplusplus.com .

+30
Nov 07 '13 at 15:08
source share

Why not just convert both strings to lowercase before you call find() ?

tolower

Note:

+9
Jun 30 '10 at 18:34
source share

why not use Boost.StringAlgo:

 #include <boost/algorithm/string/find.hpp> bool Foo() { //case insensitive find std::string str("Hello"); boost::iterator_range<std::string::const_iterator> rng; rng = boost::ifind_first(str, std::string("EL")); return rng; } 
+7
Nov 04 '14 at 11:22
source share

Since you are searching for a substring (std :: string) and not an element (character), unfortunately, there is no existing solution that I know about which is immediately available in the standard library for this.

However, it is simple enough: just convert both lines to upper case (or both to lower case - I chose upper case in this example).

 std::string upper_string(const std::string& str) { string upper; transform(str.begin(), str.end(), std::back_inserter(upper), toupper); return upper; } std::string::size_type find_str_ci(const std::string& str, const std::string& substr) { return upper(str).find(upper(substr) ); } 

This is not a quick fix (bordering the territory of pessimization), but it is the only thing I know from the hands. It is also not so difficult to implement your own case insensitive substring finder if you are concerned about efficiency.

Also, I need to support stand :: wstring / wchar_t. Any ideas?

tolower / toupper in locale will work with wide-format strings, so the above solution should be equally applicable (a simple change to std :: string to std :: wstring).

[Edit] An alternative, as indicated, is to adapt a case-insensitive string type from basic_string, specifying its own character traits. This works if you can accept all string queries, comparisons, etc., so that they are not case sensitive for a given string type.

+6
Jun 30 2018-10-18T00:
source share

It also makes sense to provide a Boost version: this will change the source lines.

 #include <boost/algorithm/string.hpp> string str1 = "hello world!!!"; string str2 = "HELLO"; boost::algorithm::to_lower(str1) boost::algorithm::to_lower(str2) if (str1.find(str2) != std::string::npos) { // str1 contains str2 } 

or using perfect speed up xpression library

 #include <boost/xpressive/xpressive.hpp> using namespace boost::xpressive; .... std::string long_string( "very LonG string" ); std::string word("long"); smatch what; sregex re = sregex::compile(word, boost::xpressive::icase); if( regex_match( long_string, what, re ) ) { cout << word << " found!" << endl; } 

In this example, you should note that your search word does not have special regular expression characters.

+3
Dec 31 '14 at 12:15
source share

If you need a β€œreal” comparison according to Unicode and locale rules, use the ICUs Collator class .

+2
Jun 30 2018-10-18T00:
source share
 #include <iostream> using namespace std; template <typename charT> struct ichar { operator charT() const { return toupper(x); } charT x; }; template <typename charT> static basic_string<ichar<charT> > *istring(basic_string<charT> &s) { return (basic_string<ichar<charT> > *)&s; } template <typename charT> static ichar<charT> *istring(const charT *s) { return (ichar<charT> *)s; } int main() { string s = "The STRING"; wstring ws = L"The WSTRING"; cout << istring(s)->find(istring("str")) << " " << istring(ws)->find(istring(L"wstr")) << endl; } 

A bit dirty, but short and fast.

0
Aug 6 '15 at 10:49
source share



All Articles