使用std :: find在std :: map中进行不区分大小写的搜索

时间:2014-04-18 12:17:45

标签: c++ algorithm dictionary stdmap

我需要通过不区分大小写的比较从矢量列表中找到字符串。如果没有使用Boost,是否有一些简单的解决方案?

我为区分大小写的搜索编写的代码是:

std::map<std::string, std::string>::const_iterator it;
if (map.end() != (it = map.find(mKey)))
    // if word matches

通过一个答案建议我使用find_if并获得以下异常。它在特定值下给出以下错误

 my_map1["$$HYPHEN{{a"] = "-"; 

enter image description here

使用lexicographical_compare尝试了代码:

std::map<std::string, std::string> map1;
std::map<std::string,
         std::string,
         bool(*)(const std::string&, const std::string&)>
     my_map_temp(case_insensitive_string_cmp);
my_map_temp["$$HYPHEN--a"] = "foo";
my_map_temp["$$HYPHEN{{a"] = "foo1";
while (my_map_temp.end() !=  my_map_temp.find("$$HYPHEn--a"))
    {
       std::cout << my_map_temp["hellOOOO"] << std::endl;
    }

但在这种情况下,如何将map1值复制到my_map_temp

1 个答案:

答案 0 :(得分:3)

std::map::find依赖于地图的内部排序。如果要使用此方法进行搜索,则需要使用不区分大小写的比较函数构建映射,也就是说,映射是不区分大小写的WRT键。

这可以通过利用std::lexicographical_compare算法轻松完成,并将其与不区分大小写的元素进行比较:

#include <cctype>
#include <algorithm>
#include <string>

bool case_insensitive_cmp(char lhs, char rhs)
{
  return std::toupper(lhs) < std::toupper(rhs);
}

bool case_insensitive_string_cmp(const std::string& lhs, 
                                 const std::string& rhs)
{
  return std::lexicographical_compare(lhs.begin(), 
                                      lhs.end(),
                                      rhs.begin(),
                                      rhs.end(),
                                      case_insensitive_cmp);
}

然后,使用不区分大小写的字符串比较函数创建映射:

std::map<std::string, 
         std::string, 
         bool(*)(const std::string&, const std::string&)> 
     my_map(case_insensitive_string_cmp);

my_map["Helloooo"] = "foo";
my_map["HELLOOOO"] = "bar";
std::cout << my_map["hellOOOO"] << std::endl;

Live demo

如果您希望地图具有标准的,区分大小写的行为,但又想要执行不区分大小写的搜索,那么您需要将std::find_if与合适的谓词一起使用。但是在这里你失去了地图的O(logN)查找的优势。

以下是标准地图中不区分大小写搜索的工作示例。在C ++ 11中,它将更加冗长:

#include <map>
#include <iostream>
#include <cctype>
#include <algorithm>
#include <string>

bool case_insensitive_eq(const char& lhs, const char& rhs)
{
    return std::toupper(lhs) == std::toupper(rhs);
}

bool case_insensitive_string_eq(const std::string& lhs, const std::string& rhs)
{
  return std::equal(lhs.begin(), 
                    lhs.end(),
                    rhs.begin(),
                    case_insensitive_eq);
}

typedef std::map<std::string, std::string> StringMap;

struct case_insensitive_key_eq
{
  case_insensitive_key_eq(const std::string& key) : key_(key) {}

  bool operator()(StringMap::value_type item) const
  {
    return case_insensitive_string_eq(item.first, key_);
  }
  std::string key_;
};

int main()
{
  StringMap my_map;

  my_map["Helloooo"] = "foo";
  StringMap::iterator it = std::find_if(my_map.begin(), 
                                        my_map.end(), 
                                        case_insensitive_key_eq("HeLlOOoo"));
  if (it != my_map.end())
  {
    std::cout << "Found element " << it->second << std::endl;
  } else
  {
    std::cout << "element not found\n";
  }
}