不区分大小写std :: string.find()

我使用std::stringfind()方法来testing一个string是否是另一个string的子string。 现在我需要不区分大小写的相同的东西。 对于string比较,我总是可以转向stricmp()但似乎没有stristr()

我已经find了各种答案,大多数人build议使用Boost ,在我的情况下,这不是一个选项。 另外,我需要支持std::wstring / wchar_t 。 有任何想法吗?

你可以使用自定义谓词来使用std::search

 #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; } 

新的C ++ 11风格:

 #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() ); } 

“search”的解释可以在cplusplus.com上find 。

为什么不在调用find()之前将这两个string转换为小写呢?

降低

注意:

  • 对于长string没有效率。
  • 谨防国际化问题 。

为什么不使用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; } 

由于你正在做子stringsearch(std :: string)而不是元素(字符)search,不幸的是我没有现在的解决scheme,我知道这是可以立即在标准库中访问来做到这一点。

尽pipe如此,这样做很简单:只需将两个string转换为大写(或者两个都转换为小写 – 在本例中我select了upper)。

 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) ); } 

这不是一个快速的解决scheme(接近悲观化的领域),但这是我所知道的唯一一个副手。 如果您担心效率,那么实现自己的不区分大小写的子string查找器也不难。

另外,我需要支持std :: wstring / wchar_t。 有任何想法吗?

在locale中tolower / toupper也可以在宽string上工作,所以上面的解决scheme应该是适用的(简单的将std :: string改为std :: wstring)。

[编辑]正如指出的,另一种方法是通过指定自己的字符特征来调整您自己的不区分大小写的basic_stringstringtypes。 如果您可以接受所有stringsearch,比较等,以便对给定的stringtypes不区分大小写,则此方法有效。

提供Boost版本也是有意义的:这将修改原始string。

 #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 } 

或者使用完美的boost压缩库

 #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; } 

在这个例子中,你应该注意你的search词没有任何正则expression式的特殊字符。

如果您想根据Unicode和区域设置规则进行“真实”比较,请使用ICU的Collator类 。

 #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; } 

有点肮脏,但又短又快。