Создание карты :: поиск недействителен

Способствует ли метод map :: find безопасному регистру поиска?
У меня есть карта следующим образом

map<string,vector > directory; 

и хотите, чтобы нижестоящий поиск игнорировал регистр.

 directory.find(search_string); 

Это не по умолчанию. В качестве третьего аргумента вам придется предоставить собственный компаратор. Следующий fragment поможет вам …

  /************************************************************************/ /* 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 } }; 

Используйте его как std::map< std::string, std::vector, ci_less > myMap;

ПРИМЕЧАНИЕ : std :: lexicographic_compare имеет некоторые подробные детали. Сравнение строк не всегда просто, если вы рассматриваете локали. См. Эту тему на clc ++, если это интересно.

UPDATE : С C ++ 11 std::binary_function устарела и не нужна, поскольку типы выводятся автоматически.

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

Вот несколько других альтернатив, в том числе тот, который выполняет значительно быстрее.

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

Вы можете создать std::map с тремя параметрами: тип ключей, тип значений и функцию сравнениястрогий слабый порядок (по существу, функция или функтор, действующий как operator< с точки зрения транзитивности и антирефлексивности) вашего симпатия. Просто определите третий параметр, чтобы сделать «нечувствительным к регистру меньше» (например, < a по сравнению с нижними строками, которые он сравнивает), и вы получите «карту без учета регистра», которую вы желаете!

Я использую следующее:

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

Если вы не хотите прикасаться к типу карты (чтобы сохранить ее оригинальную простоту и эффективность), но не против использовать более медленную функцию поиска без учета регистра (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)); } 

PS: Может быть, это была идея Роджера Пейта, но не уверена, поскольку некоторые детали были немного выключены (std :: search ?, direct string comparator?)

Нет, вы не можете сделать это с помощью find как в этом случае будет много совпадений. Например, при вставке вы можете сделать что-то вроде map["A"] = 1 и map["a"] = 2 и теперь, если вы хотите нечувствительность к регистру map.find("a") каково ожидаемое возвращаемое значение ? Самый простой способ решить эту проблему – вставить строку в карту только в одном случае (в верхнем или нижнем регистре), а затем использовать тот же случай, когда выполняете поиск.

Элементу Compare шаблона карты по умолчанию соответствует двоичный class сравнения «less». Посмотрите на реализацию:

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

Вероятно, вы можете создать свой собственный class, который происходит от binary_function (родительский class до меньшего) и сделать то же сравнение без чувствительности к регистру.

Проверено:

 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"] < 

Внесите std :: less функцию и сравните, изменив оба варианта на один и тот же случай.

Для C ++ 11 и выше:

 #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; } 
  • Функция шаблона C ++ компилируется в заголовке, но не выполняется
  • Как я могу оценить использование памяти std :: map?
  • Есть ли какой-либо реальный риск для получения из контейнеров STL C ++?
  • Зачем использовать iteratorы вместо индексов массива?
  • STL Rope - когда и где использовать
  • std :: transform () и toupper (), нет соответствующей функции
  • Объединение двух std :: векторов
  • Почему контейнеры C ++ не допускают неполные типы?
  • Как удалить элементы из контейнеров STL?
  • Как вы копируете содержимое массива в std :: vector в C ++ без цикла?
  • Почему «! =» Используется с iteratorами вместо «<»?
  • Давайте будем гением компьютера.