saber - mintomay c++
Haciendo que map:: find funcione sin distinguir entre mayúsculas y minúsculas (10)
Aquí hay algunas otras alternativas, incluida una que funciona significativamente más rápido.
#include <map>
#include <string>
#include <cstring>
#include <iostream>
#include <boost/algorithm/string.hpp>
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<string, string, bool> {
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<std::string, std::string, bool>
{
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;
}
¿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<string> > directory;
y quiere que la búsqueda a continuación ignore el caso.
directory.find(search_string);
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.
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<string, int> 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?)
Implemente la función std :: less y compare cambiando ambas al mismo caso.
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<std::string, std::string, bool>
{
// case-independent (ci) compare_less binary function
struct nocase_compare : public std::binary_function<unsigned char,unsigned char,bool>
{
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<std::string>, 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 this 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
}
};
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.
Para C ++ 11 y más allá:
#include <strings.h>
#include <map>
#include <string>
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 <typename T>
using CaseInsensitiveMap = std::map<std::string, T, detail::CaseInsensitiveComparator>;
int main(int argc, char* argv[])
{
CaseInsensitiveMap<int> m;
m["one"] = 1;
std::cout << m.at("ONE") << "/n";
return 0;
}
Probado:
template<typename T>
struct ci_less:std::binary_function<T,T,bool>
{ bool operator() (const T& s1,const T& s2) const { return boost::ilexicographical_compare(s1,s2); }};
...
map<string,int,ci_less<string>> x=boost::assign::map_list_of
("One",1)
("Two",2)
("Three",3);
cout << x["one"] << x["TWO"] <<x["thrEE"] << endl;
//Output: 123
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<std::string, std::string,
boost::function<bool(std::string const &,
std::string const &)>
> case_insensitive_map(&str_iless);