【发布时间】:2012-03-19 03:06:33
【问题描述】:
如果我有一个字符串向量,如何使用不区分大小写的比较对某个字符串进行二进制搜索?我想不出任何简单的方法来做到这一点。
【问题讨论】:
如果我有一个字符串向量,如何使用不区分大小写的比较对某个字符串进行二进制搜索?我想不出任何简单的方法来做到这一点。
【问题讨论】:
为 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
【讨论】:
我认为您需要编写自己的比较函数,它将比较两个小写变体的字符串。使用此函数,您可以对向量进行排序,然后通过这些比较器比较查询字符串。
【讨论】:
使用find_if 提供自定义谓词:
find_if (myvector.begin(), myvector.end(), MyPredicate);
http://www.cplusplus.com/reference/algorithm/find_if/
有关编写可重用谓词的帮助,另请参阅: Making map::find operation case insensitive
【讨论】:
#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
【讨论】:
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.
}
}
【讨论】:
如果您只需要知道这样的元素是否存在,请使用 std::binary_search。如果您需要访问该元素并知道它的位置,请使用 std::lower_bound。
【讨论】: