C ++ में केस-असंवेदनशील स्ट्रिंग तुलना [बंद]


373

सभी अपरकेस या सभी लोअरकेस को स्ट्रिंग में परिवर्तित किए बिना C ++ में केस-असंवेदनशील स्ट्रिंग तुलना करने का सबसे अच्छा तरीका क्या है?

कृपया बताएं कि क्या विधियां यूनिकोड के अनुकूल हैं और वे कितनी पोर्टेबल हैं।


@ [एडम] (# ११६9 ९): जबकि यह संस्करण प्रयोज्य के मामले में अच्छा है, यह प्रदर्शन के मामले में बुरा है क्योंकि यह अनावश्यक प्रतियां है। मैं कुछ अनदेखी कर सकता हूं, लेकिन मेरा मानना ​​है कि सबसे अच्छा (गैर-यूनिकोड) तरीका उपयोग करना है std::stricmp। अन्यथा, हर्ब को क्या कहना है , पढ़ें ।
कोनराड रुडोल्फ

सी में, एक आमतौर पर पूरे स्ट्रिंग को टौपर करने के लिए मजबूर किया गया था, फिर इस तरह से तुलना करें - या अपनी खुद की तुलना रोल करें: पी
माइकल डोरगन

बाद के प्रश्न का एक सरल उत्तर है: strcasecmp (कम से कम BSD और POSIX कंपाइलर के लिए) stackoverflow.com/questions/9182912/…
Móż

@ M @ इस सवाल का वह जवाब भी है, जो महत्वपूर्ण कैविएट के साथ strcasecmpहै जो मानक का हिस्सा नहीं है और कम से कम एक सामान्य संकलक से गायब है।
मार्क रैनसम

जवाबों:


317

बूस्ट में इसके लिए एक आसान एल्गोरिदम शामिल है:

#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>

std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";

if (boost::iequals(str1, str2))
{
    // Strings are identical
}

14
क्या यह UTF-8 के अनुकूल है? मुझे नहीं लगता।
vladr

18
नहीं, क्योंकि UTF-8 समान बाइनरी कोड्स, बीड़ी मुद्दों, आदि के कारण विभिन्न बाइनरी कोड के साथ कोडित होने की अनुमति देता है
vy32

10
@ vy32 यह बिल्कुल गलत है! UTF-8 संयोजन परस्पर अनन्य हैं। इसे हमेशा कम से कम संभव प्रतिनिधित्व का उपयोग करना चाहिए, अगर ऐसा नहीं होता है, तो यह एक विकृत यूटीएफ -8 अनुक्रम या कोड बिंदु है जिसे देखभाल के साथ इलाज किया जाना चाहिए।
विज

48
@, आप यूनिकोड स्ट्रिंग के सामान्यीकरण के मुद्दे की अनदेखी कर रहे हैं। a को n के बाद या ñ वर्ण के साथ संयोजन as के रूप में दर्शाया जा सकता है। आपको तुलना करने से पहले यूनिकोड स्ट्रिंग सामान्यीकरण का उपयोग करने की आवश्यकता है। कृपया यूनिकोड तकनीकी रिपोर्ट की समीक्षा करें # 15, unicode.org/reports/tr15
vy32

12
@wonkorealtime: क्योंकि "onk" को अपरकेस में बदल दिया गया है "SS": fileformat.info/info/unicode/char/df/index.htm
मूविंग डक

118

मानक का लाभ लें char_traits। स्मरण करो कि std::stringवास्तव में एक के लिए एक typedef है std::basic_string<char>, या अधिक स्पष्ट रूप से std::basic_string<char, std::char_traits<char> >,। char_traitsप्रकार वर्णन करता है कि पात्रों की तुलना, वे कैसे कॉपी, कैसे वे आदि सभी डाली आपको बस इतना करना एक नया स्ट्रिंग typedef खत्म हो गया है basic_string, और अपने स्वयं के कस्टम के साथ प्रदान करते हैं char_traitsकि insensitively मामले की तुलना करें।

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

विवरण द वीक नंबर 29 के गुरु पर है ।


10
जहाँ तक मुझे अपने स्वयं के प्रयोग से पता है, यह आपके नए स्ट्रिंग प्रकार को std :: string से असंगत बनाता है।
ज़ैन लिंक्स

8
बेशक यह करता है - अपने अच्छे के लिए। केस-असंवेदनशील स्ट्रिंग कुछ और है: typedef std::basic_string<char, ci_char_traits<char> > istringनहीं typedef std::basic_string<char, std::char_traits<char> > string
एंड्रियास स्पिंडलर

232
"आपको बस इतना करने की ज़रूरत है ..."
टिम एमबी

3
@ नथन संभवत: एक कंपाइलर का उपयोग करते हैं जो कोड पर बेसिक सीएसई प्रदर्शन करने में सक्षम है ...
पैरामैग्नेटिक क्रोइसैंट

17
किसी भी भाषा का निर्माण इस तरह के तुच्छ मामले में इस तरह के पागलपन को मजबूर करता है और बिना पछतावे के इसे छोड़ दिया जाना चाहिए।
एरिक एरोनिटी

86

बूस्ट के साथ परेशानी यह है कि आपको इसके साथ लिंक करना होगा और बढ़ावा पर निर्भर रहना होगा। कुछ मामलों में आसान नहीं है (उदाहरण के लिए Android)।

और char_traits का उपयोग करने का मतलब है कि आपकी सभी तुलनाएं असंवेदनशील हैं, जो आमतौर पर आप क्या चाहते हैं।

यह पर्याप्त होना चाहिए। यह उचित रूप से कुशल होना चाहिए। हालांकि यूनिकोड या कुछ भी नहीं संभालता है।

bool iequals(const string& a, const string& b)
{
    unsigned int sz = a.size();
    if (b.size() != sz)
        return false;
    for (unsigned int i = 0; i < sz; ++i)
        if (tolower(a[i]) != tolower(b[i]))
            return false;
    return true;
}

अपडेट: बोनस C ++ 14 संस्करण ( #include <algorithm>):

bool iequals(const string& a, const string& b)
{
    return std::equal(a.begin(), a.end(),
                      b.begin(), b.end(),
                      [](char a, char b) {
                          return tolower(a) == tolower(b);
                      });
}

27
दरअसल, बूस्ट स्ट्रिंग लाइब्रेरी एक हेडर केवल लाइब्रेरी है, इसलिए किसी भी चीज़ से लिंक करने की आवश्यकता नहीं है। इसके अलावा, आप बूस्ट हेडर को अपने स्रोत ट्री में कॉपी करने के लिए बूस्ट की 'bcp' उपयोगिता का उपयोग कर सकते हैं, इसलिए आपको पूर्ण बूस्ट लाइब्रेरी की आवश्यकता नहीं है।
ग्रेटचेन

आह, मैं bcp के बारे में नहीं जानता था, यह वास्तव में उपयोगी लगता है। जानकारी के लिए धन्यवाद!
टिम्मम्म

9
एक सरल और गैर-बढ़ावा-निर्भरता संस्करण जानने के लिए अच्छा है।
दिवाकिंग

2
@ अन्ना टेक्स्ट लाइब्रेरी ऑफ बूस्ट के निर्माण और लिंक की जरूरत है। यह आईबीएम आईसीयू का उपयोग करता है।
बेह्रोज़।

सी ++ 11 के साथ भी उपलब्ध है
मार्टियन

58

यदि आप POSIX सिस्टम पर हैं, तो आप strcasecmp का उपयोग कर सकते हैं । यह फ़ंक्शन मानक C का हिस्सा नहीं है, हालाँकि, न ही यह विंडोज पर उपलब्ध है। यह 8-बिट वर्णों पर केस-असंवेदनशील तुलना करेगा, जब तक कि लोकेल POSIX है। यदि स्थान POSIX नहीं है, तो परिणाम अपरिभाषित हैं (इसलिए यह स्थानीयकृत तुलना कर सकता है, या यह नहीं हो सकता है)। एक विस्तृत वर्ण समकक्ष उपलब्ध नहीं है।

असफल होने पर, बड़ी संख्या में ऐतिहासिक सी लाइब्रेरी कार्यान्वयनों में स्ट्रिकम्प () और स्ट्रिम्पम्प () कार्य होते हैं। विंडोज पर विजुअल C ++ ने इन सभी का नाम बदलकर उन्हें अंडरस्कोर के साथ जोड़ दिया क्योंकि वे ANSI मानक का हिस्सा नहीं हैं, इसलिए उस सिस्टम पर उन्हें _stricmp या _strnicmp कहा जाता है । कुछ पुस्तकालयों में व्यापक चरित्र या मल्टीबाइट समतुल्य कार्य हो सकते हैं (आमतौर पर नाम उदाहरण के लिए wcsicmp, mbcsicmp और इसी तरह)।

C और C ++ अंतर्राष्ट्रीयकरण के मुद्दों से काफी हद तक अनभिज्ञ हैं, इसलिए इस समस्या का कोई अच्छा समाधान नहीं है, सिवाय एक तृतीय-पक्ष लाइब्रेरी का उपयोग करने के। चेक आउट आईबीएम आईसीयू (यूनिकोड के लिए अंतर्राष्ट्रीय अवयव) यदि आप सी / सी के लिए एक मजबूत पुस्तकालय की जरूरत ++। ICU विंडोज और यूनिक्स सिस्टम दोनों के लिए है।


53

क्या आप एक गूंगे मामले के बारे में असंवेदनशील तुलना कर रहे हैं या एक पूर्ण सामान्यीकृत यूनिकोड की तुलना कर रहे हैं?

एक गूंगा तुलना में ऐसे तार नहीं मिलेंगे जो समान हो सकते हैं लेकिन बाइनरी समान नहीं हैं।

उदाहरण:

U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).

सभी समान हैं लेकिन उनके पास अलग-अलग द्विआधारी प्रतिनिधित्व भी हैं।

उस ने कहा, यूनिकोड सामान्यीकरण एक अनिवार्य रूप से पढ़ा जाना चाहिए खासकर तब जब आप हंगुल, थाओ और अन्य एशियाई भाषाओं का समर्थन करने की योजना बनाते हैं।

इसके अलावा, आईबीएम ने बहुत अधिक अनुकूलित यूनिकोड एल्गोरिदम का पेटेंट कराया और उन्हें सार्वजनिक रूप से उपलब्ध कराया। वे एक कार्यान्वयन भी बनाए रखते हैं: आईबीएम आईसीयू


2
आप उस ICU को site.icu-project.org पर
DevSolar

31

बढ़ावा :: iequals स्ट्रिंग के मामले में utf-8 संगत नहीं है। आप बढ़ावा :: लोकेल का उपयोग कर सकते हैं ।

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
  • प्राथमिक - केवल उच्चारण और चरित्र के मामले को अनदेखा करें, केवल आधार पत्रों की तुलना करें। उदाहरण के लिए "मुखौटा" और "फाकेड" समान हैं।
  • द्वितीयक - चरित्र के मामले को अनदेखा करें लेकिन उच्चारण पर विचार करें। "मुखौटा" और "अग्रभाग" अलग हैं लेकिन "फाकेड" और "अग्रभाग" समान हैं।
  • तृतीयक - मामले और लहजे दोनों पर विचार करें: "फ़ाकडे" और "अग्रभाग" अलग हैं। विराम चिह्न को अनदेखा करें।
  • चतुर्धातुक - सभी मामले, लहजे और विराम चिह्न पर विचार करें। यूनिकोड प्रतिनिधित्व के संदर्भ में शब्द समान होना चाहिए।
  • पहचान - चतुर्भुज के रूप में, लेकिन साथ ही कोड बिंदुओं की तुलना करें।

30

एक गैर-यूनिकोड संस्करण के लिए मेरा पहला विचार कुछ ऐसा करना था:


bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
    if (str1.size() != str2.size()) {
        return false;
    }
    for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
        if (tolower(*c1) != tolower(*c2)) {
            return false;
        }
    }
    return true;
}

20

आप strcasecmpयूनिक्स पर उपयोग कर सकते हैं , याstricmp विंडोज पर ।

एक बात जिसका अब तक उल्लेख नहीं किया गया है, यदि आप इन विधियों के साथ stl स्ट्रिंग्स का उपयोग कर रहे हैं, तो पहले दो स्ट्रिंग्स की लंबाई की तुलना करना उपयोगी है, क्योंकि यह जानकारी पहले से ही स्ट्रिंग क्लास में आपके लिए उपलब्ध है। यह महंगा स्ट्रिंग तुलना करने से रोक सकता है यदि आप जिस दो तार की तुलना कर रहे हैं वह पहले स्थान पर समान लंबाई नहीं है।


एक स्ट्रिंग की लंबाई निर्धारित करने के बाद से स्ट्रिंग में हर चरित्र पर पुनरावृत्ति होती है और 0 के खिलाफ तुलना होती है, क्या वास्तव में उस के बीच बहुत अंतर है और अभी स्ट्रिंग्स की तुलना करना है? मुझे लगता है कि आपको उस मामले में बेहतर मेमोरी लोकलिटी मिलती है जहां दोनों स्ट्रिंग्स मैच नहीं करते हैं, लेकिन मैच के मामले में शायद लगभग 2x रनटाइम है।
19

3
C ++ 11 निर्दिष्ट करता है कि std :: string :: length की जटिलता निरंतर होनी चाहिए: cplusplus.com/reference/string/string/length
bradtgmurray

1
यह एक मजेदार सा तथ्य है, लेकिन यहाँ बहुत कम असर पड़ता है। strcasecmp () और stricmp () दोनों अनिर्णीत C स्ट्रिंग्स लेते हैं, इसलिए इसमें कोई std :: string शामिल नहीं है।
10

3
यदि आप "a" बनाम "ab" की तुलना करते हैं तो ये विधियाँ -1 लौट आएंगी। लंबाई अलग हैं लेकिन "ए" से पहले "एब" आता है। इसलिए, यदि कॉलर ऑर्डर करने की परवाह करता है, तो लंबाई की तुलना करना संभव नहीं है।
नाथन

14

यूनिकोड का समर्थन करने वाली विज़ुअल सी ++ स्ट्रिंग फ़ंक्शंस: http://msdn.microsoft.com/en-us/library/cc194799.aspx

आप जिसे खोज रहे हैं वह है _wcsnicmp


7
विडंबना यह है कि माइक्रोसॉफ्ट के "विस्तृत चरित्र कोड" यूनिकोड स्वच्छ नहीं हैं क्योंकि वे यूनिकोड सामान्यीकरण को संभालते नहीं हैं।
v3232

13

मैं सभी पोस्ट से एक साथ एक अच्छा जवाब देने की कोशिश कर रहा हूं, इसलिए मुझे इसे संपादित करने में मदद करें:

यहाँ यह करने का एक तरीका है, हालाँकि यह स्ट्रिंग्स को रूपांतरित करता है, और यूनिकोड के अनुकूल नहीं है, यह पोर्टेबल होना चाहिए जो एक प्लस है:

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
    std::string str1Cpy( str1 );
    std::string str2Cpy( str2 );
    std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
    std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
    return ( str1Cpy == str2Cpy );
}

मैंने जो पढ़ा है, वह स्ट्रिकम्प () की तुलना में अधिक पोर्टेबल है क्योंकि स्ट्रिकम्प () वास्तव में एसटीडी लाइब्रेरी का हिस्सा नहीं है, लेकिन केवल अधिकांश कंपाइलर विक्रेताओं द्वारा कार्यान्वित किया जाता है।

वास्तव में यूनिकोड अनुकूल कार्यान्वयन प्राप्त करने के लिए यह प्रतीत होता है कि आपको एसटीडी लाइब्रेरी के बाहर जाना चाहिए। एक अच्छा 3 पार्टी पुस्तकालय आईबीएम आईसीयू (यूनिकोड के लिए अंतर्राष्ट्रीय घटक) है

इसके अलावा बढ़ावा :: iequals इस तरह की तुलना करने के लिए एक काफी अच्छी उपयोगिता प्रदान करता है।


क्या आप बता सकते हैं, इसका क्या अर्थ है :: tolower, क्यों आप tolower () के बजाय टोलवर का उपयोग कर सकते हैं, और इससे पहले '::' क्या है? धन्यवाद
VextoR

17
यह बहुत कुशल समाधान नहीं है - आप दोनों तारों की प्रतियां बनाते हैं और उन सभी को रूपांतरित करते हैं, भले ही पहला चरित्र अलग हो।
टिम्मम

2
यदि आप वैसे भी एक प्रति बनाने जा रहे हैं, तो संदर्भ के बजाय मान से क्यों नहीं गुजरना चाहिए?
celticminstrel

मुझे लगता है कि यह बिना किसी बढ़ावा के सरल टिप है। :)
cmcromance

1
सवाल स्पष्ट रूप transformसे तुलना करने से पहले पूरे स्ट्रिंग को नहीं पूछता है
सैंडबर्ग

12
str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

आप C ++ 14 में उपरोक्त कोड का उपयोग कर सकते हैं यदि आप बूस्ट का उपयोग करने की स्थिति में नहीं हैं। आपको std::towlowerविस्तृत वर्णों के लिए उपयोग करना होगा।


4
मुझे लगता है कि आपको एक जोड़ने की जरूरत है str1.size() == str2.size() && सामने ताकि जब बीआर 2 स्ट्रिफ़ का उपसर्ग हो तो सीमा से बाहर न जाए।
14euroburɳ

11

Boost.String पुस्तकालय केस-insenstive की तुलना करते समय और इतने पर के लिए एल्गोरिदम का एक बहुत है।

आप अपने स्वयं के कार्यान्वयन कर सकते हैं, लेकिन जब यह पहले से ही हो चुका है तो परेशान क्यों?


1
वहाँ एक रास्ता नहीं है जिसमें एसटीडी :: स्ट्रिंग के साथ अंतर्निहित है?
विलियमकेएफ

6
नहीं, वहाँ नहीं है।
डीन हार्डिंग

3
"... जब यह पहले से ही किया गया है तो परेशान क्यों?" - क्या होगा अगर आप बूस्ट का इस्तेमाल नहीं कर रहे हैं? ओपी के पास सवाल के साथ टैग नहीं था।
22

11

FYI करें, strcmp()और stricmp()बफर अतिप्रवाह के लिए असुरक्षित हैं, क्योंकि वे एक शून्य टर्मिनेटर को हिट करने तक सिर्फ प्रक्रिया करते हैं। यह उपयोग करने के लिए सुरक्षित है _strncmp()और _strnicmp()


6
यह सच है, हालाँकि बफर को ओवरराइड करना बफर की तुलना में बहुत कम खतरनाक है।
एडम रोसेनफील्ड

4
stricmp()और strnicmp()POSIX मानक का हिस्सा :-( लेकिन अगर आप पा सकते हैं नहीं कर रहे हैं strcasecmp(), strcasecmp_l(), strncasecmp()और strncasecmp_l()POSIX शीर्षक में strings.h:-) देख opengroup.org
olibre

2
@AdamRosenfield 'बदतर' संदर्भ पर निर्भर करता है। सुरक्षा में, कभी-कभी ओवरराइट करने के लिए पूरे बिंदु को ओवरराइड करना होता है।
कर्मकाज़े

10

देखें std::lexicographical_compare:

// lexicographical_compare example
#include <iostream>  // std::cout, std::boolalpha
#include <algorithm>  // std::lexicographical_compare
#include <cctype>  // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
    return std::tolower(c1) < std::tolower(c2);
}

int main () {
    char foo[] = "Apple";
    char bar[] = "apartment";

    std::cout << std::boolalpha;

    std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";

    std::cout << "Using default comparison (operator<): ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
    std::cout << '\n';

    std::cout << "Using mycomp as comparison object: ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
    std::cout << '\n';

    return 0;
}

डेमो


यह विधि संभावित रूप से असुरक्षित और गैर-पोर्टेबल है। std::tolowerयदि चरित्र ASCII- एन्कोडेड है तभी काम करता है। इसके लिए ऐसी कोई गारंटी नहीं है std::string- इसलिए यह आसानी से अपरिभाषित व्यवहार हो सकता है।
प्लाज़मासेल

@plasmacel तब एक फ़ंक्शन का उपयोग करें जो w / अन्य एन्कोडिंग का काम करता है।
ब्रायन रोड्रिगेज

9

मेरे मूल मामले के लिए असंवेदनशील स्ट्रिंग तुलना की जरूरत है कि मैं एक बाहरी पुस्तकालय का उपयोग नहीं करना चाहता हूं, और न ही मैं मामले के प्रति असंवेदनशील लक्षणों के साथ एक अलग स्ट्रिंग वर्ग चाहता हूं जो मेरे अन्य सभी तार के साथ असंगत है।

तो मैं इसके साथ आया हूँ:

bool icasecmp(const string& l, const string& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](string::value_type l1, string::value_type r1)
                { return toupper(l1) == toupper(r1); });
}

bool icasecmp(const wstring& l, const wstring& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](wstring::value_type l1, wstring::value_type r1)
                { return towupper(l1) == towupper(r1); });
}

चार के लिए एक अधिभार के साथ एक साधारण कार्य और दूसरे के लिए whar_t। किसी भी मंच पर ठीक नहीं होना चाहिए, इसलिए कुछ भी गैर-मानक का उपयोग नहीं करता है।

समानता की तुलना चर लंबाई एन्कोडिंग और यूनिकोड सामान्यीकरण जैसे मुद्दों पर विचार नहीं करेगी, लेकिन basic_string के पास इसके लिए कोई समर्थन नहीं है कि मैं वैसे भी जागरूक हूं और यह सामान्य रूप से कोई समस्या नहीं है।

ऐसे मामलों में जहां पाठ के अधिक परिष्कृत लेक्सोग्राफिक हेरफेर की आवश्यकता होती है, तो आपको बस बूस्ट जैसे तीसरे पक्ष के पुस्तकालय का उपयोग करना होगा, जो कि अपेक्षित है।


2
आप शायद इसे एक फंक्शन बना सकते हैं यदि आपने इसे एक टेम्प्लेट बनाया है और अलग स्ट्रिंग / wstring संस्करणों के बजाय basic_string <T> का उपयोग किया है?
19

2
एकल फ़ंक्शन टेम्पलेट विशेषीकरण या मैक्रोज़ के उपयोग का सहारा लिए बिना टॉपर या टॉपर को कैसे लागू करेगा, एक फ़ंक्शन अधिभार या तो एक सरल और अधिक उपयुक्त कार्यान्वयन की तरह लगता है।
न्यूट्रिनो

9

छोटा और अच्छा। कोई अन्य निर्भरता नहीं, विस्तारित std सी lib से।

strcasecmp(str1.c_str(), str2.c_str()) == 0

रिटर्न सच अगर str1और str2बराबर हैं। strcasecmpमौजूद नहीं हो सकता है, हो सकता है एनालॉग stricmp, strcmpiआदि

उदाहरण कोड:

#include <iostream>
#include <string>
#include <string.h> //For strcasecmp(). Also could be found in <mem.h>

using namespace std;

/// Simple wrapper
inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) {
    if(s1.length() != s2.length())
        return false;  // optimization since std::string holds length in variable.
    return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}

/// Function object - comparator
struct StringCaseInsensetiveCompare {
    bool operator()(std::string const& s1, std::string const& s2) {
        if(s1.length() != s2.length())
            return false;  // optimization since std::string holds length in variable.
        return strcasecmp(s1.c_str(), s2.c_str()) == 0;
    }
    bool operator()(const char *s1, const char * s2){ 
        return strcasecmp(s1,s2)==0;
    }
};


/// Convert bool to string
inline char const* bool2str(bool b){ return b?"true":"false"; }

int main()
{
    cout<< bool2str(strcasecmp("asd","AsD")==0) <<endl;
    cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0) <<endl;
    StringCaseInsensetiveCompare cmp;
    cout<< bool2str(cmp("A","a")) <<endl;
    cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"})) <<endl;
    return 0;
}

आउटपुट:

true
true
true
true
true

6
यह अजीब है कि C ++ std :: string में कोई
इग्नोर

1
"स्ट्रैसेकम्प मानक का हिस्सा नहीं है" - मार्क रैनसम 1 दिसंबर 14 को 19:57
Liviu

हां, लेकिन अधिकांश आधुनिक संकलक में इसका या इसके नाम का दूसरा एनालॉग है। stricmp, strcmpi, strcasecmp, आदि धन्यवाद। संदेश संपादित किया गया।
कीब

TODO: cout << boolalphaमेरे बजाय उपयोग bool2strक्योंकि यह स्पष्ट रूप से धारा के लिए बूल को वर्णों में परिवर्तित करता है।
कीब

यह gcc के पुस्तकालयों में <strings.h> है।
उल्लू

7

बूस्ट का उपयोग किए बिना ऐसा करना C स्ट्रिंग पॉइंटर को प्राप्त करने c_str()और उपयोग करने के द्वारा किया जा सकता है strcasecmp:

std::string str1 ="aBcD";
std::string str2 = "AbCd";;
if (strcasecmp(str1.c_str(), str2.c_str()) == 0)
{
    //case insensitive equal 
}

6

यह मानते हुए कि आप एक विधि की तलाश कर रहे हैं, न कि एक जादू की क्रिया जो पहले से मौजूद है, वहाँ स्पष्ट रूप से कोई बेहतर तरीका नहीं है। हम सभी सीमित चरित्र सेट के लिए चालाक चाल के साथ कोड स्निपेट लिख सकते हैं, लेकिन किसी बिंदु पर दिन के अंत में आपको पात्रों को बदलना होगा।

इस रूपांतरण के लिए सबसे अच्छा तरीका तुलना से पहले ऐसा करना है। यह आपको एन्कोडिंग योजनाओं की बात करने पर लचीलेपन का एक अच्छा सौदा देता है, जिससे आपके वास्तविक तुलना ऑपरेटर को अनभिज्ञ होना चाहिए।

आप निश्चित रूप से अपने स्वयं के स्ट्रिंग फ़ंक्शन या वर्ग के पीछे इस रूपांतरण को 'छिपा' सकते हैं, लेकिन आपको अभी भी तुलना करने से पहले स्ट्रिंग को परिवर्तित करने की आवश्यकता है।


6

मैंने std के साथ उपयोग के लिए char_traits का एक केस-असंवेदनशील संस्करण लिखा है :: मूल_स्ट्रीमिंग एक std उत्पन्न करने के लिए :: स्ट्रिंग जो केस-संवेदी नहीं है, जब अंतर्निहित एसटीडी का उपयोग करके तुलना, खोजों आदि का उपयोग किया जा रहा है :: मूल-सदस्य सदस्य फ़ंक्शन।

इसलिए दूसरे शब्दों में, मैं ऐसा कुछ करना चाहता था।

std::string a = "Hello, World!";
std::string b = "hello, world!";

assert( a == b );

... जो std :: string हैंडल नहीं कर सकता। यहाँ मेरे नए char_traits का उपयोग किया गया है:

std::istring a = "Hello, World!";
std::istring b = "hello, world!";

assert( a == b );

... और यहाँ कार्यान्वयन है:

/*  ---

        Case-Insensitive char_traits for std::string's

        Use:

            To declare a std::string which preserves case but ignores case in comparisons & search,
            use the following syntax:

                std::basic_string<char, char_traits_nocase<char> > noCaseString;

            A typedef is declared below which simplifies this use for chars:

                typedef std::basic_string<char, char_traits_nocase<char> > istring;

    --- */

    template<class C>
    struct char_traits_nocase : public std::char_traits<C>
    {
        static bool eq( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) == ::toupper(c2); 
        }

        static bool lt( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) < ::toupper(c2);
        }

        static int compare( const C* s1, const C* s2, size_t N )
        {
            return _strnicmp(s1, s2, N);
        }

        static const char* find( const C* s, size_t N, const C& a )
        {
            for( size_t i=0 ; i<N ; ++i )
            {
                if( ::toupper(s[i]) == ::toupper(a) ) 
                    return s+i ;
            }
            return 0 ;
        }

        static bool eq_int_type( const int_type& c1, const int_type& c2 )
        { 
            return ::toupper(c1) == ::toupper(c2) ; 
        }       
    };

    template<>
    struct char_traits_nocase<wchar_t> : public std::char_traits<wchar_t>
    {
        static bool eq( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) == ::towupper(c2); 
        }

        static bool lt( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) < ::towupper(c2);
        }

        static int compare( const wchar_t* s1, const wchar_t* s2, size_t N )
        {
            return _wcsnicmp(s1, s2, N);
        }

        static const wchar_t* find( const wchar_t* s, size_t N, const wchar_t& a )
        {
            for( size_t i=0 ; i<N ; ++i )
            {
                if( ::towupper(s[i]) == ::towupper(a) ) 
                    return s+i ;
            }
            return 0 ;
        }

        static bool eq_int_type( const int_type& c1, const int_type& c2 )
        { 
            return ::towupper(c1) == ::towupper(c2) ; 
        }       
    };

    typedef std::basic_string<char, char_traits_nocase<char> > istring;
    typedef std::basic_string<wchar_t, char_traits_nocase<wchar_t> > iwstring;

1
यह नियमित वर्णों के लिए काम करता है, लेकिन यूनिकोड के सभी के लिए काम नहीं करेगा, क्योंकि वशीकरण आवश्यक रूप से द्विदिश नहीं है (ग्रीक में एक अच्छा उदाहरण है जिसमें सिग्मा शामिल है जिसे मैं अभी याद नहीं कर सकता; कुछ ऐसा है कि इसमें दो निचले और एक ऊपरी मामला है। , और आप किसी भी तरह से एक उचित तुलना नहीं कर सकते हैं)
21

1
यह वास्तव में इसके बारे में जाने का गलत तरीका है। केस सेंसिटिविटी खुद स्ट्रिंग्स की प्रॉपर्टी नहीं होनी चाहिए। क्या होता है जब समान स्ट्रिंग ऑब्जेक्ट को केस-संवेदी और केस असंवेदनशील तुलना दोनों की आवश्यकता होती है?
फेरुचियो

यदि केस-सेंसिटिविटी को "स्ट्रिंग" का हिस्सा बनने के लिए उपयुक्त नहीं है, तो न तो खोज () फ़ंक्शन है। जो, आपके लिए, सच हो सकता है, और यह ठीक है। IMO C ++ की सबसे बड़ी बात यह है कि यह प्रोग्रामर पर किसी विशेष प्रतिमान को लागू नहीं करता है। यह वही है जो आप चाहते हैं / इसे होना चाहिए।
जॉन डिब्लिंग

वास्तव में, मुझे लगता है कि ज्यादातर सी ++ - गुरु की (मानकों समिति पर लोगों की तरह) सहमत हैं कि इसे खोजने में एक गलती थी () std :: basic_string <> कई अन्य चीजों के साथ जो समान रूप से अच्छी तरह से रखा जा सकता है। मुक्त कार्य। इसके अलावा इसे टाइप में डालने के साथ कुछ मुद्दे हैं।
एंड्रियास मैग्यूसन

जैसा कि अन्य ने बताया है, इस समाधान के साथ दो प्रमुख बातें गलत हैं (विडंबना यह है कि एक इंटरफ़ेस है और दूसरा कार्यान्वयन है; ;-))।
कोनराड रुडोल्फ

4

मुझे यूनिकोड पुस्तकालयों के लिए अंतर्राष्ट्रीय अवयवों का उपयोग करने का अच्छा अनुभव है - वे बेहद शक्तिशाली हैं, और रूपांतरण, स्थान समर्थन, दिनांक और समय प्रदान करने, केस मैपिंग (जो आप नहीं चाहते हैं), और टकराव के लिए तरीके प्रदान करते हैं। , जिसमें मामला- और उच्चारण-असंवेदनशील तुलना (और अधिक) शामिल हैं। मैंने केवल पुस्तकालयों के C ++ संस्करण का उपयोग किया है, लेकिन उनके पास जावा संस्करण भी है।

तरीके सामान्य रूप से तुलना करने के लिए मौजूद हैं, जैसे कि @Coincoin द्वारा संदर्भित किया गया है, और यहां तक ​​कि लोकेल के लिए भी खाता हो सकता है - उदाहरण के लिए (और यह एक छँटाई उदाहरण है, कड़ाई से समानता नहीं), पारंपरिक रूप से स्पेनिश में (स्पेन में), अक्षर संयोजन "ll" के बीच में होता है "l" और "m", इसलिए "lz" <"ll" <"ma"।


4

बस strcmp()केस संवेदनशील और strcmpi()या stricmp()असंवेदनशील तुलना के लिए उपयोग करें । जो हेडर फाइल में दोनों हैं<string.h>

प्रारूप:

int strcmp(const char*,const char*);    //for case sensitive
int strcmpi(const char*,const char*);   //for case insensitive

उपयोग:

string a="apple",b="ApPlE",c="ball";
if(strcmpi(a.c_str(),b.c_str())==0)      //(if it is a match it will return 0)
    cout<<a<<" and "<<b<<" are the same"<<"\n";
if(strcmpi(a.c_str(),b.c_str()<0)
    cout<<a[0]<<" comes before ball "<<b[0]<<", so "<<a<<" comes before "<<b;

उत्पादन

सेब और ApPlE समान हैं

b से पहले आता है, इसलिए सेब गेंद से पहले आता है


2
Downvote क्योंकि यह शायद ही चीजों को करने का C ++ तरीका है।
थॉमस दौगार्ड

यह मेरे विश्वविद्यालय में c ++ कन्वेंशन है, लेकिन मैं यहां पोस्ट करते समय इसे ध्यान में
रखूंगा

4
stricmp एक Microsoft एक्सटेंशन AFAIK है। लगता है BSD के बजाय strcasecmp () है।
13

3

पार्टी के लिए देर हो चुकी है, लेकिन यहां एक प्रकार है जो उपयोग करता है std::locale, और इस प्रकार सही ढंग से तुर्की को संभालता है:

auto tolower = std::bind1st(
    std::mem_fun(
        &std::ctype<char>::tolower),
    &std::use_facet<std::ctype<char> >(
        std::locale()));

आपको एक फ़ंक्टर देता है जो वर्णों को लोअरकेस में बदलने के लिए सक्रिय लोकेल का उपयोग करता है, जिसे आप लो std::transform-केस स्ट्रेंथ उत्पन्न करने के लिए उपयोग कर सकते हैं:

std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);

यह भी wchar_tआधारित स्ट्रिंग्स के लिए काम करता है ।


2

जो भी विधि आप अंततः चुनते हैं, उस पर ध्यान दें, यदि वह विधि strcmpकुछ उत्तरों के सुझाव का उपयोग शामिल करने के लिए होती है:

strcmpसामान्य रूप से यूनिकोड डेटा के साथ काम नहीं करता है। सामान्य तौर पर, यह बाइट-आधारित यूनिकोड एन्कोडिंग के साथ भी काम नहीं करता है, जैसे कि utf-8, क्योंकि strcmpकेवल बाइट-प्रति-बाइट तुलना करता है और यूटीकोड -8 में कूटबद्ध अंक 1 से अधिक बाइट ले सकता है। केवल विशिष्ट यूनिकोड मामला strcmpठीक से संभालता है जब एक स्ट्रिंग बाइट-आधारित एन्कोडिंग के साथ एन्कोडेड होता है, केवल U + 00FF के नीचे कोड बिंदु होते हैं - तब बाइट-प्रति-बाइट तुलना पर्याप्त होती है।


2

2013 की शुरुआत में, आईबीएम द्वारा बनाए रखा गया आईसीयू प्रोजेक्ट, इसका एक अच्छा जवाब है।

http://site.icu-project.org/

आईसीयू एक "पूर्ण, पोर्टेबल यूनिकोड लाइब्रेरी है जो उद्योग मानकों को बारीकी से ट्रैक करता है।" स्ट्रिंग तुलना की विशिष्ट समस्या के लिए, Collation ऑब्जेक्ट वह करता है जो आप चाहते हैं।

मोज़िला परियोजना ने 2012 के मध्य में फ़ायरफ़ॉक्स में अंतर्राष्ट्रीयकरण के लिए आईसीयू को अपनाया; आप इंजीनियरिंग चर्चा को ट्रैक सिस्टम और डेटा फ़ाइल आकार के मुद्दों सहित ट्रैक कर सकते हैं:


2

ऐसा लगता है कि उपरोक्त समाधान तुलना पद्धति का उपयोग नहीं कर रहे हैं और कुल को फिर से लागू कर रहे हैं इसलिए मेरा समाधान है और आशा है कि यह आपके लिए काम करता है (यह ठीक काम कर रहा है)।

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
string tolow(string a)
{
    for(unsigned int i=0;i<a.length();i++)
    {
        a[i]=tolower(a[i]);
    }
    return a;
}
int main()
{
    string str1,str2;
    cin>>str1>>str2;
    int temp=tolow(str1).compare(tolow(str2));
    if(temp>0)
        cout<<1;
    else if(temp==0)
        cout<<0;
    else
        cout<<-1;
}

1

यदि आप बूस्ट लाइब्रेरी का उपयोग नहीं करना चाहते हैं, तो इसका समाधान केवल C ++ मानक io हैडर का उपयोग करके किया जा सकता है।

#include <iostream>

struct iequal
{
    bool operator()(int c1, int c2) const
    {
        // case insensitive comparison of two characters.
        return std::toupper(c1) == std::toupper(c2);
    }
};

bool iequals(const std::string& str1, const std::string& str2)
{
    // use std::equal() to compare range of characters using the functor above.
    return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());
}

int main(void)
{
    std::string str_1 = "HELLO";
    std::string str_2 = "hello";

    if(iequals(str_1,str_2))
    {
        std::cout<<"String are equal"<<std::endl;   
    }

    else
    {
        std::cout<<"String are not equal"<<std::endl;
    }


    return 0;
}

मेरा मानना ​​है कि std :: toupper #include <cctype> में है, आपको इसे शामिल करने की आवश्यकता हो सकती है।
डेविड लेजर 12

यदि आप इस तरह के वैश्विक संस्करण का उपयोग करेंगे :: टॉपर तो आपको <ctype> को शामिल करने की आवश्यकता नहीं हो सकती है क्योंकि स्थानीय संस्करण के साथ दो संस्करण c संस्करण और c ++ संस्करण हैं। वैश्विक संस्करण "::
टॉपर

यह समाधान विफल हो जाता है जब तार में से एक खाली होता है: "" - यह उस स्थिति में सच होता है जब इसे गलत लौटना चाहिए
ekkis

0

यदि आपको किसी अन्य स्रोत के साथ अधिक बार एक स्रोत स्ट्रिंग की तुलना करनी है, तो रेगेक्स का उपयोग करने के लिए एक सुरुचिपूर्ण समाधान है।

std::wstring first = L"Test";
std::wstring second = L"TEST";

std::wregex pattern(first, std::wregex::icase);
bool isEqual = std::regex_match(second, pattern);

इस लेकिन संकलन त्रुटि की कोशिश की: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing

बुरा विचार। इसका सबसे बुरा हल है।
बेह्रोज़।

यह एक अच्छा समाधान नहीं है, लेकिन यहां तक ​​कि अगर आप इसका उपयोग करना चाहते हैं, तो आपको अपने चौड़ी स्थिरांक के सामने एक एल की आवश्यकता है, जैसे एल "टेस्ट"
केल्टिकमिनस्ट्रेल

अच्छा होगा यदि कोई समझा सकता है कि यह सबसे खराब समाधान क्यों है। प्रदर्शन के मुद्दों की वजह से? रेगेक्स बनाना महंगा है, लेकिन बाद में तुलना वास्तव में तेज होनी चाहिए।
स्माइली

यह प्रयोग करने योग्य और पोर्टेबल है, प्रमुख समस्या यह है कि पहले किसी भी वर्ण को शामिल नहीं किया जा सकता है जो रेगेक्स का उपयोग करता है। इसकी वजह से सामान्य स्ट्रिंग की तुलना में इसका उपयोग नहीं किया जा सकता है। यह धीमा भी होगा, इस तरह से काम करने के लिए एक ध्वज है जो स्माइब कहता है लेकिन फिर भी इसे सामान्य फ़ंक्शन के रूप में उपयोग नहीं किया जा सकता है।
बेन

0

C ++ में दो स्ट्रिंग की तुलना करने का एक सरल तरीका (विंडोज़ के लिए परीक्षण किया गया) _stricmp का उपयोग कर रहा है

// Case insensitive (could use equivalent _stricmp)  
result = _stricmp( string1, string2 );  

यदि आप std :: string, उदाहरण के साथ उपयोग करना चाह रहे हैं:

std::string s1 = string("Hello");
if ( _stricmp(s1.c_str(), "HELLO") == 0)
   std::cout << "The string are equals.";

यहां अधिक जानकारी के लिए: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx


यह इस जवाब के अलावा stackoverflow.com/a/12414441/95309 पढ़ने लायक है , क्योंकि यह ए) सी फ़ंक्शन है, और बी) माना जाता है कि पोर्टेबल नहीं है।
क्लॉस जोर्जेंसन

इस कार्य को करने के लिए हमें क्या करना होगा?
21

1
@ekkis _stricmp का उपयोग करने के लिए आपको <string.h> को शामिल करना होगा, जैसा कि आप यहाँ पढ़ सकते हैं: docs.microsoft.com/en-us/cpp/c-runtime-library/reference/…
DAme

-1
bool insensitive_c_compare(char A, char B){
  static char mid_c = ('Z' + 'a') / 2 + 'Z';
  static char up2lo = 'A' - 'a'; /// the offset between upper and lowers

  if ('a' >= A and A >= 'z' or 'A' >= A and 'Z' >= A)
      if ('a' >= B and B >= 'z' or 'A' >= B and 'Z' >= B)
      /// check that the character is infact a letter
      /// (trying to turn a 3 into an E would not be pretty!)
      {
        if (A > mid_c and B > mid_c or A < mid_c and B < mid_c)
        {
          return A == B;
        }
        else
        {
          if (A > mid_c)
            A = A - 'a' + 'A'; 
          if (B > mid_c)/// convert all uppercase letters to a lowercase ones
            B = B - 'a' + 'A';
          /// this could be changed to B = B + up2lo;
          return A == B;
        }
      }
}

यह शायद बहुत अधिक कुशल बनाया जा सकता है, लेकिन यहाँ अपने सभी बिट्स नंगे के साथ एक भारी संस्करण है।

यह सब पोर्टेबल नहीं है, लेकिन मेरे कंप्यूटर पर जो कुछ भी है उसके साथ अच्छी तरह से काम करता है (कोई विचार नहीं, मैं चित्रों का हूं शब्दों का नहीं)


यह यूनिकोड समर्थन नहीं है जो कि सवाल पूछा गया है।
बेह्रोज़।

यह गैर-अंग्रेजी वर्ण सेट का समर्थन नहीं करता है।
रॉबर्ट एंड्रीजुक

-3

स्ट्रिंग्स की तुलना करने का एक आसान तरीका जो केवल लोअरकेस और कैपिटलाइज्ड कैरेक्टर्स द्वारा अलग-अलग है, एक एससीआई तुलना करना है। सभी पूंजी और लोअरकेस अक्षर एससीआई तालिका में 32 बिट्स से भिन्न होते हैं, इस जानकारी का उपयोग करके हम निम्नलिखित हैं ...

    for( int i = 0; i < string2.length(); i++)
    {
       if (string1[i] == string2[i] || int(string1[i]) == int(string2[j])+32 ||int(string1[i]) == int(string2[i])-32) 
    {
      count++;
      continue;
    }
    else 
    {
      break;
    }
    if(count == string2.length())
    {
      //then we have a match
    }
}

3
इसके अनुसार, "++ जे" "केकेजे" के बराबर पाया जाएगा, और "1234" "क्यूआरजे" के बराबर पाया जाएगा। मुझे संदेह है कि कोई भी व्यक्ति कुछ भी चाहता है।
celticminstrel
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.