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

时间:2010-06-30 18:28:28

标签: c++ string stl case-insensitive wstring

我正在使用std::string的{​​{1}}方法来测试字符串是否是另一个字符串的子字符串。现在我需要不区分大小写的同一件事。对于字符串比较,我总是可以转到find(),但似乎没有stricmp()

我找到了各种答案,大多数建议使用stristr(),这在我的案例中不是一个选项。此外,我需要支持Boost / std::wstring。有什么想法吗?

10 个答案:

答案 0 :(得分:68)

您可以将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;
}

答案 1 :(得分:43)

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

可以在cplusplus.com上找到std :: search的说明。

答案 2 :(得分:11)

为什么不在拨打find()之前将两个字符串转换为小写?

tolower

注意:

答案 3 :(得分:9)

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

答案 4 :(得分:8)

由于您正在进行子字符串搜索(std :: string)而不是元素(字符)搜索,遗憾的是我没有现有的解决方案可以在标准库中立即访问,以便执行此操作。

尽管如此,这很容易做到:只需将两个字符串转换为大写字母(或两者都转换为小写字母 - 在本例中我选择了字符串)。

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

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

  

另外,我需要支持   的std :: wstring的/ wchar_t的。有什么想法吗?

语言环境中的

tolower / toupper也适用于宽字符串,因此上面的解决方案应该同样适用(简单地将std :: string更改为std :: wstring)。

[编辑]正如所指出的,另一种方法是通过指定自己的角色特征来调整basic_string中不区分大小写的字符串类型。如果您可以接受所有字符串搜索,比较等对给定字符串类型不区分大小写,则此方法有效。

答案 5 :(得分:3)

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

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

在此示例中,您应该注意搜索词没有任何正则表达式特殊字符。

答案 6 :(得分:2)

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

答案 7 :(得分:0)

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

有点脏,但短而且快。

答案 8 :(得分:0)

我喜欢Kiril V. LyadvinskyCC的答案。但是我的问题不仅仅是不区分大小写。我需要一个懒惰的,受Unicode支持的命令行参数解析器,该解析器在处理字母数字字符串搜索时可以消除错误的正数/负数,而字母数字字符串搜索的基本字符串中可能包含特殊字符,这些字符串用于格式化我要搜索的字母数字关键字,例如{{1 }}不应该与Wolfjäger相匹配,而jäger应该与之匹配。

基本上,这只是Kiril / CC的答案,需要对字母数字精确长度匹配进行额外的处理。

<jäger>

答案 9 :(得分:0)

wxWidgets具有非常丰富的字符串API wxString

可以(使用大小写转换方式)

int Contains(const wxString& SpecProgramName, const wxString& str)
{
  wxString SpecProgramName_ = SpecProgramName.Upper();
  wxString str_ = str.Upper();
  int found = SpecProgramName.Find(str_);
  if (wxNOT_FOUND == found)
  {
    return 0;
  }
  return 1;
}