代码之家  ›  专栏  ›  技术社区  ›  wpfwannabe

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

  •  54
  • wpfwannabe  · 技术社区  · 14 年前

    我正在使用 std::string find() 方法来测试一个字符串是否是另一个字符串的子字符串。现在我需要一个不区分大小写的版本。对于字符串比较,我总是可以求助于 stricmp() stristr() .

    我找到了各种各样的答案,大多数建议使用 Boost 在我的情况下这不是一个选择。另外,我需要支持 std::wstring wchar_t . 有什么想法吗?

    9 回复  |  直到 14 年前
        1
  •  78
  •   Drew Dormann    10 年前

    你可以用 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;
    }
    
        2
  •  62
  •   CC.    7 年前

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

    有关std::搜索的说明,请参见 cplusplus.com .

        3
  •  18
  •   gast128    7 年前

    为什么不使用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
  •  17
  •   DavidS    9 年前
        5
  •  8
  •   stinky472    14 年前

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

    另外,我需要支持 标准::wstring/wchar\t。有什么想法吗?

    [编辑]如前所述,另一种方法是通过指定自己的字符特征,使自己的字符串类型不区分大小写。如果您可以接受对给定字符串类型不区分大小写的所有字符串搜索、比较等,则可以使用这种方法。

        6
  •  2
  •   Philipp    14 年前

    如果要根据Unicode和区域设置规则进行真正的比较,请使用 ICU’s Collator class .

        7
  •  2
  •   Boris Ivanov    11 年前

    提供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;
    }
    

    在本例中,您应该注意您的搜索词没有任何regex特殊字符。

        8
  •  0
  •   rejkowic    9 年前
    #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;
    }
    

    有点脏,但是短&快。

        9
  •  0
  •   kayleeFrye_onDeck    6 年前

    Kiril V. Lyadvinsky CC . 但我的问题比不区分大小写要具体一些;我需要一个懒惰的Unicode支持的命令行参数解析器,在处理字母数字字符串搜索时,它可以消除误报/漏报,而字母数字字符串搜索的基字符串中可能包含用于格式化我搜索的字母数字关键字的特殊字符,例如。, Wolfjäger 不应该匹配 jäger 但是 <jäger> 应该。

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

    /* Undefined behavior when a non-alpha-num substring parameter is used. */
    bool find_alphanum_string_CI(const std::wstring& baseString, const std::wstring& subString)
    {
        /* Fail fast if the base string was smaller than what we're looking for */
        if (subString.length() > baseString.length()) 
            return false;
    
        auto it = std::search(
            baseString.begin(), baseString.end(), subString.begin(), subString.end(),
            [](char ch1, char ch2)
            {
                return std::toupper(ch1) == std::toupper(ch2);
            }
        );
    
        if(it == baseString.end())
            return false;
    
        size_t match_start_offset = it - baseString.begin();
    
        std::wstring match_start = baseString.substr(match_start_offset, std::wstring::npos);
    
        /* Typical special characters and whitespace to split the substring up. */
        size_t match_end_pos = match_start.find_first_of(L" ,<.>;:/?\'\"[{]}=+-_)(*&^%$#@!~`");
    
        /* Pass fast if the remainder of the base string where
           the match started is the same length as the substring. */
        if (match_end_pos == std::wstring::npos && match_start.length() == subString.length()) 
            return true;
    
        std::wstring extracted_match = match_start.substr(0, match_end_pos);
    
        return (extracted_match.length() == subString.length());
    }
    
        10
  •  -2
  •   Pedro Vicente    5 年前

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

    可以使用(使用case转换方式)

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