Haciendo que map :: find funcione sin distinguir entre mayúsculas y minúsculas

¿El mapa :: encuentra el método de soporte de búsqueda insensible a mayúsculas y minúsculas?
Tengo un mapa de la siguiente manera

map<string,vector > directory; 

y quiere que la búsqueda a continuación ignore el caso.

 directory.find(search_string); 

No por defecto. Deberá proporcionar un comparador personalizado como tercer argumento. El siguiente fragmento te ayudará …

  /************************************************************************/ /* Comparator for case-insensitive comparison in STL assos. containers */ /************************************************************************/ struct ci_less : std::binary_function { // case-independent (ci) compare_less binary function struct nocase_compare : public std::binary_function { bool operator() (const unsigned char& c1, const unsigned char& c2) const { return tolower (c1) < tolower (c2); } }; bool operator() (const std::string & s1, const std::string & s2) const { return std::lexicographical_compare (s1.begin (), s1.end (), // source range s2.begin (), s2.end (), // dest range nocase_compare ()); // comparison } }; 

Úselo como std::map< std::string, std::vector, ci_less > myMap;

NOTA : std :: lexicographical_compare tiene algunos detalles esenciales. La comparación de cadenas no siempre es sencilla si se consideran configuraciones regionales. Vea este hilo en clc ++ si está interesado.

ACTUALIZACIÓN : Con C ++ 11 std::binary_function está en desuso y es innecesario ya que los tipos se deducen automáticamente.

  struct ci_less { // case-independent (ci) compare_less binary function struct nocase_compare { bool operator() (const unsigned char& c1, const unsigned char& c2) const { return tolower (c1) < tolower (c2); } }; bool operator() (const std::string & s1, const std::string & s2) const { return std::lexicographical_compare (s1.begin (), s1.end (), // source range s2.begin (), s2.end (), // dest range nocase_compare ()); // comparison } }; 

Aquí hay algunas otras alternativas, incluida una que funciona significativamente más rápido.

 #include  #include  #include  #include  #include  using std::string; using std::map; using std::cout; using std::endl; using namespace boost::algorithm; // recommended in Meyers, Effective STL when internationalization and embedded // NULLs aren't an issue. Much faster than the STL or Boost lex versions. struct ciLessLibC : public std::binary_function { bool operator()(const string &lhs, const string &rhs) const { return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ; } }; // Modification of Manuel's answer struct ciLessBoost : std::binary_function { bool operator() (const std::string & s1, const std::string & s2) const { return lexicographical_compare(s1, s2, is_iless()); } }; typedef map< string, int, ciLessLibC> mapLibc_t; typedef map< string, int, ciLessBoost> mapBoost_t; int main(void) { mapBoost_t cisMap; // change to test other comparitor cisMap["foo"] = 1; cisMap["FOO"] = 2; cisMap["bar"] = 3; cisMap["BAR"] = 4; cisMap["baz"] = 5; cisMap["BAZ"] = 6; cout << "foo == " << cisMap["foo"] << endl; cout << "bar == " << cisMap["bar"] << endl; cout << "baz == " << cisMap["baz"] << endl; return 0; } 

Puede instanciar std::map con tres parámetros: tipo de teclas, tipo de valores y función de comparación : un orden estricto y débil (esencialmente, una función o functor que se comporta como operator< en términos de transitividad y antirreflexión) de su gusto. Simplemente defina el tercer parámetro para hacer "insensible a mayúsculas y minúsculas menor que" (por ejemplo, con un < en las cadenas minúsculas que está comparando) y tendrá el "mapa insensible a mayúsculas y minúsculas" que desee.

Yo uso lo siguiente:

 bool str_iless(std::string const & a, std::string const & b) { return boost::algorithm::lexicographical_compare(a, b, boost::is_iless()); } std::map > case_insensitive_map(&str_iless); 

En caso de que no desee tocar el tipo de mapa (para mantener su simplicidad y eficacia originales), pero no le moleste usar una función de búsqueda menos sensible a mayúsculas y minúsculas (O (N)):

 string to_lower(string s) { transform(s.begin(), s.end(), s.begin(), (int(*)(int)) tolower ); return s; } typedef map map_type; struct key_lcase_equal { string lcs; key_lcase_equal(const string& s) : lcs(to_lower(s)) {} bool operator()(const map_type::value_type& p) const { return to_lower(p.first) == lcs; } }; map_type::iterator find_ignore_case(map_type& m, const string& s) { return find_if(m.begin(), m.end(), key_lcase_equal(s)); } 

PD: Tal vez fue idea de Roger Pate, pero no estoy seguro, ya que algunos detalles estaban un poco desajustados (std :: search ?, ¿comparador directo de cadenas?)

No, no puedes hacer eso usando find ya que en ese caso habrá múltiples coincidencias. Por ejemplo, al insertar, le permite hacer algo como map["A"] = 1 y map["a"] = 2 y ahora si desea un caso insensible map.find("a") cuál es el valor de retorno esperado ? La forma más sencilla de resolver esto sería insertar la cadena en el mapa en un solo caso (ya sea en mayúscula o minúscula) y luego usar el mismo estuche al hacer el hallazgo.

El elemento Comparar de la plantilla de mapa tiene como valor predeterminado una clase de comparación binaria “menos”. Mira la implementación:

http://www.cplusplus.com/reference/std/functional/less/

Es probable que pueda crear su propia clase que se deriva de binary_function (la clase principal a menos) y hacer la misma comparación sin mayúsculas y minúsculas.

Probado:

 template struct ci_less:std::binary_function { bool operator() (const T& s1,const T& s2) const { return boost::ilexicographical_compare(s1,s2); }}; ... map> x=boost::assign::map_list_of ("One",1) ("Two",2) ("Three",3); cout << x["one"] << x["TWO"] < 

Implemente la función std :: less y compare cambiando ambas al mismo caso.

Para C ++ 11 y más allá:

 #include  #include  #include  namespace detail { struct CaseInsensitiveComparator { bool operator()(const std::string& a, const std::string& b) const noexcept { return ::strcasecmp(a.c_str(), b.c_str()) < 0; } }; } // namespace detail template  using CaseInsensitiveMap = std::map; int main(int argc, char* argv[]) { CaseInsensitiveMap m; m["one"] = 1; std::cout << m.at("ONE") << "\n"; return 0; }