【问题标题】:How to use STL to do a case insensitive binary search for a string如何使用 STL 对字符串进行不区分大小写的二进制搜索
【发布时间】:2012-03-19 03:06:33
【问题描述】:

如果我有一个字符串向量,如何使用不区分大小写的比较对某个字符串进行二进制搜索?我想不出任何简单的方法来做到这一点。

【问题讨论】:

标签: c++ stl


【解决方案1】:

为 std::sort 提供比较函数,将容器排序为小写(使用 boost 字符串算法来帮助),

然后在排序后的向量上做一个二进制字符串,再次提供一个不区分大小写的比较操作来做到这一点。

使用 lambda 表达式真的很有帮助

如果使用find,则不必先排序,但是如果要进行频繁搜索并且集合很大,则速度很慢。

编辑:这里是示例

#include <boost/algorithm/string.hpp>
#include <algorithm>
::::

auto comp=[](const std::string& a, const std::string& b){   
   return boost::ilexicographical_compare
                       <std::string, std::string>(a,b);
});

std::sort(vs.begin(), vs.end(), comp);
std::binary_search(vs.begin(), vs.end(), value_to_search_for, comp);

如果您不打算对列表进行排序,则相同的比较函数也适用于 std::find。

测试

http://en.cppreference.com/w/cpp/algorithm/find

http://en.cppreference.com/w/cpp/algorithm/binary_search

http://en.cppreference.com/w/cpp/algorithm/sort

【讨论】:

  • 我刚刚阅读了比较要求 boost::algorithm::is_iless 就是你所需要的。
  • 查看编辑后的代码:应该是 ilexicographical_compare
【解决方案2】:

您可以使用 algorithm 标头中的 find 来定位容器中的特定值,但我认为它不使用二进制搜索算法(在将容器传递给之前没有先决条件对容器进行排序) find)。更多详情请见here

binary_search 也有 algorithm,更多详情 here

【讨论】:

    【解决方案3】:

    我认为您需要编写自己的比较函数,它将比较两个小写变体的字符串。使用此函数,您可以对向量进行排序,然后通过这些比较器比较查询字符串。

    【讨论】:

      【解决方案4】:

      使用find_if 提供自定义谓词:

      find_if (myvector.begin(), myvector.end(), MyPredicate);
      

      http://www.cplusplus.com/reference/algorithm/find_if/

      有关编写可重用谓词的帮助,另请参阅: Making map::find operation case insensitive

      【讨论】:

        【解决方案5】:
        #include <vector>
        #include <string>
        #include <algorithm>
        #include <iostream>
        #include <strings.h> // strncasecmp()
        
        inline int icompare(std::string const& a, std::string const& b) {
            size_t a_len = a.size(), b_len = b.size();
            size_t cmp_len = std::min(a_len, b_len);
            // strncasecmp() is a non-standard function, use the one available for your platform.
            if(int r = strncasecmp(a.data(), b.data(), cmp_len))
                return r;
            return (a_len > b_len) - (a_len < b_len);
        }
        
        struct LessNoCase {
            bool operator()(std::string const& a, std::string const& b) const {
                return icompare(a, b) < 0;
            }
        };
        
        template<class Iterator, class T>
        Iterator binary_search_caseless(Iterator beg, Iterator end, T const& value) {
            Iterator i = std::lower_bound(beg, end, value, LessNoCase());
            return i != end && !icompare(*i, value)
                ? i   // found
                : end // not found
                ;
        }
        
        int main() {
            char const* strings[] = {
                "abc",
                "def",
                "ghi"
            };
        
            std::vector<std::string> v(
                strings + 0,
                strings + sizeof strings / sizeof *strings
                );
        
            // prepare for binary search
            std::sort(v.begin(), v.end(), LessNoCase());
        
            // do the binary search
            std::cout << "index of 'abc' is " << binary_search_caseless(v.begin(), v.end(), "ABC") - v.begin() << '\n';
            std::cout << "index of 'ABC' is " << binary_search_caseless(v.begin(), v.end(), "ABC") - v.begin() << '\n';
            std::cout << "index of 'DEF' is " << binary_search_caseless(v.begin(), v.end(), "DEF") - v.begin() << '\n';
            std::cout << "index of 'xyz' is " << binary_search_caseless(v.begin(), v.end(), "xyz") - v.begin() << '\n';
        }
        

        输出:

        ./test
        index of 'abc' is 0
        index of 'ABC' is 0
        index of 'DEF' is 1
        index of 'xyz' is 3
        

        【讨论】:

          【解决方案6】:

          std::find 不支持谓词参数,因此您要查找的正确算法是std::find_if

          std::find_if( vec.begin(), vec.end(), InsensitiveCompare("search string") );
          

          ...其中InsensitiveCompare 是一个函子,它返回true 以进行不区分大小写的比较。例如:

          struct InsensitiveCompare
          {
            std::string comp;
          
            InsensitiveCompare( std::string const &s ) : comp(s) {}
          
            bool operator() ( std::string const &test ) const
            {
              // return true here if test compares with comp.
            }
          }
          

          【讨论】:

            【解决方案7】:

            如果您只需要知道这样的元素是否存在,请使用 std::binary_search。如果您需要访问该元素并知道它的位置,请使用 std::lower_bound。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-02-24
              • 1970-01-01
              • 2012-12-20
              • 2010-09-12
              • 2021-06-14
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多