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

wpf*_*abe 58 c++ string stl case-insensitive wstring

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

我找到了各种答案,大多数建议使用Boost哪个不是我的选择.另外,我需要支持std::wstring/ wchar_t.有任何想法吗?

Kir*_*sky 72

您可以使用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;
}
Run Code Online (Sandbox Code Playgroud)

  • 对“std::toupper”的调用实际上适用于宽字符吗?您不需要调用“std::towupper”吗? (4认同)
  • 完善!路要走! (2认同)
  • 为什么在这里使用模板? (2认同)

CC.*_*CC. 50

新的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() );
}
Run Code Online (Sandbox Code Playgroud)

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

  • 在这种情况下不需要模板.对于C++ 17,您可能需要查看string_view而不是std :: string https://skebanga.github.io/string-view/ (3认同)

Dav*_*idS 13

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

降低

注意:

  • 因为对于较大的琴弦来说效率非常低. (11认同)
  • 如果您的软件需要本地化,这也不是一个好主意。请参阅土耳其测试:http://haacked.com/archive/2012/07/05/turkish-i-problem-and-why-you-should-care.aspx/ (2认同)

gas*_*128 13

为什么不使用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;
}
Run Code Online (Sandbox Code Playgroud)

  • 通常,除非为Boost标记了C ++问题,否则假定Boost不是一个选择。 (2认同)

sti*_*472 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) );
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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