在 C++ 中,查找字符串向量中的字符串(不区分大小写)

6

I have

std::vector<std::string> vec;
std::string myString; 

我需要查找vec中是否包含不区分大小写的字符串myString

我知道可以使用

find(vec.begin(), vec.end(), myString) != vec.end())

回答问题“myString是否在vec中?”需要进行区分大小写的比较。我需要进行不区分大小写的比较。

位置并不重要,我只想知道myString是否在vec中。


这个能解决问题吗?在此输入链接说明 - tomascapek
相关问题 - jotik
6个回答

4
你需要使用std::tolower和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
我喜欢这个答案,但是...代码实际上是有问题的。为了修复它:if (std::tolower(s[i]) != std::tolower(newServerName[i])) return true; return false;因此,请更改比较并交换返回值。否则所有具有匹配第一个字符的字符串都被认为是相等的... - ur.

4

或者,对于一个更小且易于阅读的解决方案,可以考虑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));

在哪个星球上,Boost库才会“更小”? - EML

3

您需要使用std::find_if并提供自定义比较器。为了实现不区分大小写的比较,建议将要比较的两个字符串转换为相同的大小写:小写或大写。这将导致以下代码:

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

这将返回一个迭代器,如果没有找到myString的任何匹配项,则将返回vec.end(),您可以对该迭代器执行任何操作(包括与vec.end()进行比较以知道是否找到了字符串)。
奖励:在Coliru上运行最小示例。

@jotik 我想要表达完整的意思,他可以随意使用返回的迭代器。可以将其与vec.end()进行简单比较,也可以计算出现次数(或其他任何操作)。 - Rerito
1
没有std::toupper(std::string&)这个函数,它只接受一个字符。 - marcinj
请注意,此解决方案不适用于Unicode字符串。 - Vincent

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

使用:

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

2
您可以使用std::find_if、内联lambda和std::tolower进行比较:
//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();

如果你要在同一个字符串向量中进行多次搜索,最好在一次计算后再进行搜索:

//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();

2
std::tolower 接受一个字符而不是 std::string - marcinj

0

由于 std::find 的性能优于 std::count,因此我必须实现一个函数模板来在 std::vector 中进行搜索:

template <class Iterator>
Iterator Find(Iterator first, Iterator last, const char *value)
{
    while (first != last)
    {
        if (StrCmpIA((*first).c_str(), value) == 0)
        {
            return first;
        }

        first++;
    }

    return last;
}

现在你可以像这样使用模板函数:

vector<string> vecStr = {"ali", "reza", "hamid", "saeed"};

if (Find(vecStr.begin(), vecStr.end(), "saeeD") != vecStr.end())
{
    cout << "found" << endl;
}
else
{
    cout << "not found" << endl;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接