问题
I have
std::vector<std::string> vec;
std::string myString;
and I need to find out if myString
is in vec
using case insensitive comaprisons.
I know I can use
find(vec.begin(), vec.end(), myString) != vec.end())
to answer the question "is myString in vec?" but that will do case sensitive comparisons. I need case insensitive comparisons.
The position is not important, I just want to know if myString is in vec or not.
回答1:
Or, for a much smaller and easier-to-read solution, Boost!
// #include <algorithm>
// #include <boost/algorithm/string/predicate.hpp>
const auto it = std::find_if(
std::begin(vec),
std::end(vec),
[&myString](const auto& str) { return boost::iequals(myString, str); }
);
const bool found = (it != std::end(vec));
回答2:
You need to use std::tolower and std::find_if:
std::vector<std::string> vec = {"ALF", "B"};
std::string toSearch = "Alf";
auto itr = std::find_if(vec.begin(), vec.end(),
[&](auto &s) {
if ( s.size() != toSearch.size() )
return false;
for (size_t i = 0; i < s.size(); ++i)
if (::tolower(s[i]) == ::tolower(toSearch[i]))
return true;
return false;
}
);
if ( itr != vec.end()) {
std::cout << *itr << std::endl;
}
回答3:
You need to use std::find_if
and provide a custom comparator. To achieve case insensitive comparison I would advise you to convert both strings you want to compare to a common case: lower or upper. That would lead to a code like the following:
auto ret = std::find_if(vec.begin(), vec.end(),
[&myString](const std::string& s) {
if (s.size() != myString.size())
return false;
return std::equal(s.cbegin(), s.cend(), myString.cbegin(), myString.cend(), [](auto c1, auto c2) { return std::toupper(c1) == std::toupper(c2); });
});
This will return an iterator which will be vec.end()
if no occurrence of myString
was found. You can do whatever you please with that iterator (including comparing it to vec.end()
to know if you found your string).
Bonus: running minimal example on Coliru
回答4:
You may use std::find_if
, an inline lambda and std::tolower
to make the comparison:
//Computing the lower version of mystring
std::string my_string_lower;
my_string_lower.reserve(mystring.size());
std::transform(mystring.begin(), mystring.end(), std::back_inserter(my_string_lower), ::tolower);
// Checking if it is exist in the vector:
auto is_exist = std::find_if(vec.begin(), vec.end(), [&my_string_lower](std::string item){
//Transform the each vector item to lower temporally
std::transform(item.begin(), item.end(), item.begin(), ::tolower);
return mystring==item;
}) != vec.end();
if you are going to search many times in the same vetor of string, it would be better if you compute it once:
//Computing the lower version of the whole vector
std::vector<std::string> vec_lower;
vec_lower.reserve(vec.size());
std::transform(vec.begin(), vec.end(), std::back_inserter(vec_lower),[](std:string item){
std::transform(item.begin(), item.end(), item.begin(), ::tolower);
return item;
});
//Computing the lower version of mystring
std::string my_string_lower;
my_string_lower.reserve(mystring.size());
std::transform(mystring.begin(), mystring.end(), std::back_inserter(my_string_lower), ::tolower);
// Checking if it is exist in the lower version of the vector:
auto is_exist = std::find_if(vec_lower.begin(), vec_lower.end(), [&my_string_lower](const std::string& item){
return mystring==item;
}) != vec_lower.end();
回答5:
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const std::string& sFind ) {
return VecFindIgnoreCase( vec, sFind.c_str() );
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const char* sFind )
{
for ( std::vector< T >::const_iterator iter = vec.begin(); iter != vec.end(); ++iter )
if ( _stricmp( (*iter).c_str(), sFind ) == 0 )
return (long)std::distance( vec.begin(), iter );
return -1;
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const std::wstring& sFind ) {
return VecFindIgnoreCase( vec, sFind.c_str() );
}
template <class T>
long VecFindIgnoreCase( const std::vector< T >& vec, const wchar_t* sFind )
{
for ( std::vector< T >::const_iterator iter = vec.begin(); iter != vec.end(); ++iter )
if ( _wcsicmp( (*iter).c_str(), sFind ) == 0 )
return (long)std::distance( vec.begin(), iter );
return -1;
}
Use:
#include <string>
#include <vector>
void TestCode()
{
std::vector< std::string > strvecA;
std::vector< std::wstring > strvecW;
strvecA.push_back("abc");
strvecA.push_back("def");
strvecA.push_back("ghi");
strvecW.push_back(L"abc");
strvecW.push_back(L"def");
strvecW.push_back(L"ghi");
long ind;
ind = VecFindIgnoreCase( strvecA, "ABC" ); // ind = 0 found
ind = VecFindIgnoreCase( strvecA, "ghI" ); // ind = 2 found
ind = VecFindIgnoreCase( strvecA, "Xyz" ); // ind = -1 not found
ind = VecFindIgnoreCase( strvecW, L"aBc" ); // ind = 0 found
ind = VecFindIgnoreCase( strvecW, L"DEF" ); // ind = 1 found
ind = VecFindIgnoreCase( strvecW, L"xyZ" ); // ind = -1 not found
std::string sFind( "mno" );
if ( (ind = VecFindIgnoreCase( strvecA, sFind )) >= 0 ) {
// found at strvecA[ind]
} else {
// not found
}
}
来源:https://stackoverflow.com/questions/36494584/find-string-in-vector-of-strings-case-insensitive-c