كيف يمكنني جعل الخريطة::العثور على العملية القضية حساسة ؟

StackOverflow https://stackoverflow.com/questions/1801892

سؤال

لا map::find طريقة دعم قضية حساسة البحث ؟ لدي خريطة على النحو التالي:

map<string, vector<string> > directory;

وتريد البحث أدناه إلى تجاهل القضية:

directory.find(search_string);
هل كانت مفيدة؟

المحلول

وولا افتراضيا. سيكون لديك لتوفير المقارنة العرف بوصفه حجة ثالثة. سوف التالية تساعدك على قصاصة ...

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

استخدم ذلك مثل std::map< std::string, std::vector<std::string>, ci_less > myMap;

ملاحظة : لالأمراض المنقولة جنسيا :: lexicographical_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    <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;
}

يمكنك إنشاء مثيل std::map مع ثلاثة المعلمات:نوع من المفاتيح نوع من القيم ، وظيفة مقارنة - وهو صارمة ضعف الطلب (أساسا ، وظيفة أو functor يتصرف مثل operator< حيث للأفعال تعدى ومكافحة الفعل المنعكس) من ترضيك.مجرد تحديد المعلمة الثالث أن تفعل "حالة الأحرف أقل مما كان" (مثلا ، قبل < على lowercased سلاسل إنه مقارنة) وسيكون لديك "حالة الأحرف الخريطة" التي تريدها!

وأنا استخدم ما يلي:

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

في حال كنت لا تريد أن تلمس نوع خريطة (للحفاظ على انها البساطة الأصلية والكفاءة)، ولكن لا مانع من استخدام أبطأ وظيفة اكتشاف حالة الأحرف (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));
}

وPS: ربما كان فكرة روجر بات، ولكن لم تكن متأكدا، حيث أن بعض التفاصيل قليلا قبالة

(الأمراض المنقولة جنسيا :: بحث ؟، مقارنة سلسلة مباشرة؟)

لا، لا يمكنك أن تفعل ذلك باستخدام find كما في هذه الحالة سوف تكون هناك مباريات متعددة. على سبيل المثال، في حين ادخال يتيح كنت قد فعلت شيئا مثل map["A"] = 1 وmap["a"] = 2 والآن إذا كنت ترغب في حالة map.find("a") حساسة ما هي قيمة العائد المتوقع؟ إن أبسط طريقة لحل هذه يتم إدراج السلسلة إلى خريطة في حالة واحدة فقط (إما حالة العلوي أو السفلي) ثم باستخدام نفس القضية أثناء القيام الاكتشاف.

ووقارن عنصر من عناصر التخلف خريطة القالب إلى فئة مقارنة ثنائية "أقل". نظرة على التنفيذ:

http://www.cplusplus.com/reference/std/functional/ أقل /

ويمكنك على الأرجح إنشاء فئة الخاصة بك التي تستمد من binary_function (الفئة الأصل إلى أقل) والقيام المقارنة نفسها دون حساسية القضية.

واختبار:

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

لC ++ 11 وبعده:

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

وتنفيذ الأمراض المنقولة جنسيا :: أقل وظيفة والمقارنة بينها حسب تغيير على حد سواء لنفس القضية.

وأود أن تقديم حل قصير دون استخدام دفعة أو القوالب. منذ C ++ 11 الذي يمكن أيضا أن توفر <لأ href = "HTTPS : //en.cppreference.com/w/cpp/language/lambda "يختلط =" نوفولو noreferrer "> التعبير امدا كأساس للمقارنة مخصصة لخريطتك. لنظام POSIX متوافقة، والحل يمكن أن ننظر على النحو التالي:

auto comp = [](const std::string& s1, const std::string& s2) {
    return strcasecmp(s1.c_str(), s2.c_str()) < 0;
};
std::map<std::string, std::vector<std::string>, decltype(comp)> directory(comp);

القانون المتعلق Ideone

لالنافذة، strcasecmp() لا وجود لها، ولكن يمكنك استخدام <لأ href = "https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stricmp-wcsicmp-mbsicmp-stricmp-l-wcsicmp-l-mbsicmp-l" يختلط = "نوفولو noreferrer"> _stricmp() بدلا من ذلك:

auto comp = [](const std::string& s1, const std::string& s2) {
    return _stricmp(s1.c_str(), s2.c_str()) < 0;
};
std::map<std::string, std::vector<std::string>, decltype(comp)> directory(comp);

ملحوظة: اعتمادا على النظام الخاص بك، وإذا كان لديك لدعم Unicode أو لا، قد تحتاج إلى مقارنة سلاسل بطريقة مختلفة. هذا Q & A يعطي بداية جيدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top