मैं केस-असंवेदनशील स्ट्रिंग तुलना कैसे करूं?


573

मैं पायथन में असंवेदनशील स्ट्रिंग तुलना कैसे कर सकता हूं?

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

जवाबों:


595

ASCII स्ट्रिंग्स मानते हुए:

string1 = 'Hello'
string2 = 'hello'

if string1.lower() == string2.lower():
    print("The strings are the same (case insensitive)")
else:
    print("The strings are NOT the same (case insensitive)")

71
वह हमेशा काम नहीं करता है। निर्वासन के लिए विचार करें कि दो ग्रीक सिग्मा हैं, एक केवल अंत में उपयोग किया जाता है। स्ट्रिंग Σίσυφος ( "Sísyphos", या बेहतर "Sísyphos") सभी तीन है: मोर्चे पर अपरकेस, अंत में अंतिम लोअरकेस, और तीसरे स्थान पर nonfinal लोअरकेस। यदि आपके दो तार हैं Σίσυφοςऔर ΣΊΣΥΦΟΣफिर, आपका दृष्टिकोण विफल हो जाता है, क्योंकि वे एक ही मामले असंवेदनशील माना जाता है।
tchrist

52
@ अंतिम दो टिप्पणीकार: मुझे लगता है कि यह मानना ​​उचित है कि दोनों तार अस्सी के तार हैं। यदि आप किसी चीज़ के उत्तर की तलाश में हैं तो थोड़ा और रोमांचक होगा मुझे यकीन है कि यह वहाँ है (या आप इसे पूछ सकते हैं)।
हार्ले होल्कोम्ब जुले

16
समस्या: 'ß'.lower() == 'SS'.lower()गलत है।
kennytm

11
ग्रीक अक्षर केवल विशेष मामला नहीं है! अमेरिकी अंग्रेजी में, चरित्र "i" (\ u0069) "I" (\ u0049) चरित्र का निचला संस्करण है। हालाँकि, तुर्की ("tr-TR") वर्णमाला में "I with डॉट" वर्ण "İ" (\ u0130) शामिल है, जो "i" का कैपिटल संस्करण है और "I" बिना "i" का कैप्टिव संस्करण है। एक डॉट "चरित्र," ı "(\ u0131)।
Gqqnbig

20
@HarleyHolcombe यह कैसे सुरक्षित (या उचित) है कि तार असिसी हैं? प्रश्न निर्दिष्ट नहीं किया गया था, और यदि तार किसी भी बिंदु पर किसी उपयोगकर्ता द्वारा दर्ज किए गए या दिखाए गए हैं, तो आपको अंतर्राष्ट्रीयकरण का समर्थन करना चाहिए। भले ही, नए प्रोग्रामर इसे पढ़ रहे हों और हमें उन्हें सही उत्तर देना चाहिए।
ईथन रीसोर

529

किसी मामले में असंवेदनशील तरीके से तार की तुलना तुच्छ लगती है, लेकिन ऐसा नहीं है। मैं पायथन 3 का उपयोग कर रहा हूं, क्योंकि पायथन 2 यहां अविकसित है।

ध्यान देने वाली पहली बात यह है कि यूनिकोड में केस हटाने वाले रूपांतरण तुच्छ नहीं हैं। जिसके लिए पाठ है text.lower() != text.upper().lower(), जैसे "ß":

"ß".lower()
#>>> 'ß'

"ß".upper().lower()
#>>> 'ss'

लेकिन मान लीजिए कि आप लापरवाही से तुलना करना चाहते हैं "BUSSE"और "Buße"। हेक, आप शायद तुलना "BUSSE"और "BUẞE"बराबर करना चाहते हैं - यह नया पूंजी रूप है। उपयोग करने के लिए अनुशंसित तरीका है casefold:

str। केसफ़ॉल्ड ()

स्ट्रिंग की एक Casefolded प्रतिलिपि लौटाएँ। केसफॉल्ड स्ट्रिंग्स का उपयोग केसलेस मिलान के लिए किया जा सकता है।

Casefolding लोअरकेसिंग के समान है लेकिन अधिक आक्रामक है क्योंकि यह एक स्ट्रिंग में सभी मामले के अंतर को हटाने का इरादा है। [...]

सिर्फ उपयोग न करें lower। यदि casefoldउपलब्ध नहीं है, तो .upper().lower()मदद करना (लेकिन केवल कुछ हद तक)।

फिर आपको लहजे पर विचार करना चाहिए। यदि आपका फॉन्ट रेंडरर अच्छा है, तो आप शायद सोचते हैं "ê" == "ê"- लेकिन यह नहीं है:

"ê" == "ê"
#>>> False

ऐसा इसलिए है क्योंकि उत्तरार्द्ध पर उच्चारण एक संयोजन चरित्र है।

import unicodedata

[unicodedata.name(char) for char in "ê"]
#>>> ['LATIN SMALL LETTER E WITH CIRCUMFLEX']

[unicodedata.name(char) for char in "ê"]
#>>> ['LATIN SMALL LETTER E', 'COMBINING CIRCUMFLEX ACCENT']

इससे निपटने का सबसे सरल तरीका है unicodedata.normalize। आप शायद NFKD सामान्यीकरण का उपयोग करना चाहते हैं , लेकिन प्रलेखन की जांच करने के लिए स्वतंत्र महसूस करें। फिर एक करता है

unicodedata.normalize("NFKD", "ê") == unicodedata.normalize("NFKD", "ê")
#>>> True

समाप्त करने के लिए, यहाँ यह कार्य में व्यक्त किया गया है:

import unicodedata

def normalize_caseless(text):
    return unicodedata.normalize("NFKD", text.casefold())

def caseless_equal(left, right):
    return normalize_caseless(left) == normalize_caseless(right)

8
एक बेहतर उपाय यह है कि आप सेवन पर अपने सभी तार को सामान्य कर लें, फिर आप केवल x.casefold() == y.casefold()केस-असंवेदनशील तुलना के लिए कर सकते हैं (और, अधिक महत्वपूर्ण बात, x == yकेस-सेंसिटिव के लिए)।
अचानक

3
@abarnert वास्तव में, संदर्भ के आधार पर - कभी-कभी स्रोत को छोड़ना बेहतर होता है, लेकिन अग्रिम सामान्यीकरण भी बाद के कोड को बहुत सरल बना सकता है।
विड्राक

3
@ वीद्रेक: आप सही कह रहे हैं, यह हमेशा उचित नहीं है; यदि आपको मूल स्रोत को अपरिवर्तित करने में सक्षम होने की आवश्यकता है (उदाहरण के लिए, क्योंकि आप लिनक्स पर फ़ाइल नाम के साथ काम कर रहे हैं, जहां NKFC और NKFD दोनों की अनुमति है और स्पष्ट रूप से अलग माना जाता है), जाहिर है आप इसे इनपुट पर नहीं बदल सकते ...
अचानक

7
यूनिकोड स्टैंडर्ड सेक्शन 3.13 में कैसलेस तुलना के लिए दो अन्य परिभाषाएँ हैं: (D146, विहित) NFD(toCasefold(NFD(str)))दोनों तरफ और (D147, संगतता) NFKD(toCasefold(NFKD(toCasefold(NFD(X)))))दोनों तरफ। यह बताता है कि आंतरिक NFDरूप से एक निश्चित ग्रीक उच्चारण चरित्र को संभालने के लिए है। मुझे लगता है कि यह सब किनारे के मामलों के बारे में है।

2
और चेरोकी वर्णमाला के साथ थोड़ा सा मज़ा, जहां केसफॉल्ड () अपरकेस में जाता है: >>>। "। ऊपरी () 'ᏚᎢᎵᎬᎢᎬᏒ' >>>" ᏚᎢᎵᎬᎢᎬᏒ "। निचला () 'ꮪꭲꮅꭼꭲꭼꮢ' >>>" ᏚᎢᎵᎬᎢᎬᏒ "। .casefold () 'ᏚᎢᎵᎬᎢᎬᏒ' >>>
bortzmeyer

60

पायथन 2 का उपयोग करना, .lower()प्रत्येक स्ट्रिंग या यूनिकोड ऑब्जेक्ट पर कॉल करना ...

string1.lower() == string2.lower()

... अधिकांश समय काम करेगा, लेकिन वास्तव में @tchrist ने जिन स्थितियों का वर्णन किया है, उसमें काम नहीं करता है

मान लें कि हमारे पास एक फाइल है, unicode.txtजिसमें दो तार हैं Σίσυφοςऔर ΣΊΣΥΦΟΣ। पायथन 2 के साथ:

>>> utf8_bytes = open("unicode.txt", 'r').read()
>>> print repr(utf8_bytes)
'\xce\xa3\xce\xaf\xcf\x83\xcf\x85\xcf\x86\xce\xbf\xcf\x82\n\xce\xa3\xce\x8a\xce\xa3\xce\xa5\xce\xa6\xce\x9f\xce\xa3\n'
>>> u = utf8_bytes.decode('utf8')
>>> print u
Σίσυφος
ΣΊΣΥΦΟΣ

>>> first, second = u.splitlines()
>>> print first.lower()
σίσυφος
>>> print second.lower()
σίσυφοσ
>>> first.lower() == second.lower()
False
>>> first.upper() == second.upper()
True

Σ वर्ण के दो निचले रूप हैं, Σ और and, और .lower()केस-असंवेदनशील रूप से उनकी तुलना करने में मदद नहीं करेगा।

हालाँकि, पायथन 3 के रूप में, सभी तीन रूप and पर हल होंगे, और दोनों स्ट्रिंग्स पर कम () कॉलिंग सही ढंग से काम करेगी:

>>> s = open('unicode.txt', encoding='utf8').read()
>>> print(s)
Σίσυφος
ΣΊΣΥΦΟΣ

>>> first, second = s.splitlines()
>>> print(first.lower())
σίσυφος
>>> print(second.lower())
σίσυφος
>>> first.lower() == second.lower()
True
>>> first.upper() == second.upper()
True

इसलिए यदि आप ग्रीक में तीन सिगमा की तरह किनारे-मामलों की परवाह करते हैं, तो पायथन 3 का उपयोग करें।

(संदर्भ के लिए, पायथन 2.7.3 और पायथन 3.3.0b1 को इंटरप्रेटर प्रिंटआउट में दिखाया गया है)।


20
तुलना को और अधिक मजबूत बनाने के लिए, Python 3.3 के साथ शुरू करने से आप केसफॉल्ड (जैसे, first.casefold () == second.casefold ()) का उपयोग कर सकते हैं। अजगर 2 के लिए आप PyICU का उपयोग कर सकते हैं (यह भी देखें: icu-project.org/apiref/icu4c/… )
kgriffs

42

यूनिकोड मानक की धारा ३.१३ कैसलेस मिलान के लिए एल्गोरिदम को परिभाषित करती है।

X.casefold() == Y.casefold() पायथन 3 में "डिफॉल्ट केसलेस मैचिंग" (D144) लागू होता है।

Casefolding सभी उदाहरणों में स्ट्रिंग्स के सामान्यीकरण को संरक्षित नहीं करती है और इसलिए सामान्यीकरण की आवश्यकता है ( 'å'बनाम 'å')। D145 "कैनोनिकल केसलेस मिलान" का परिचय देता है:

import unicodedata

def NFD(text):
    return unicodedata.normalize('NFD', text)

def canonical_caseless(text):
    return NFD(NFD(text).casefold())

NFD() U + 0345 वर्ण से जुड़े बहुत ही अनपेक्षित किनारे के मामलों के लिए दो बार कहा जाता है।

उदाहरण:

>>> 'å'.casefold() == 'å'.casefold()
False
>>> canonical_caseless('å') == canonical_caseless('å')
True

वहाँ भी इस तरह के रूप मामलों के लिए अनुकूलता caseless मिलान (D146) कर रहे हैं '㎒'(U + 3392) और "पहचानकर्ता caseless मिलान" सरल करने के लिए और अनुकूलन पहचानकर्ता के caseless मिलान


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

दुर्भाग्य से, पायथन 3.6 के रूप में, casefold()फ़ंक्शन अपरकेस I और बिंदीदार अपरकेस के विशेष केस उपचार को लागू नहीं करता है जैसा कि केस फोल्डिंग गुणों में वर्णित है । इसलिए, तुर्क भाषा के उन शब्दों के लिए तुलना विफल हो सकती है जिनमें वे अक्षर हैं। उदाहरण के लिए, canonical_caseless('LİMANI') == canonical_caseless('limanı')लौटना चाहिए True, लेकिन यह वापस आ जाता है False। वर्तमान में, पायथन में इससे निपटने का एकमात्र तरीका केसफ़ॉल्ड रैपर लिखना या बाह्य यूनिकोड लाइब्रेरी का उपयोग करना है, जैसे कि PyICU।
SergiyKolesnikov

@SergiyKolesnikov .casefold () जहां तक ​​मुझे बताना चाहिए, यह व्यवहार करता है। मानक से: " विशेष भाषाओं और वातावरणों के लिए टेलरिंग की अनुपस्थिति में उपयोग के लिए डिफ़ॉल्ट आवरण संचालन का इरादा है" । तुर्की डॉटेड कैपिटल I और डॉटलेस स्माल आई के लिए केसिंग नियम स्पेशलकास्टिंग में हैं। "गैर-तुर्क भाषाओं के लिए, इस मानचित्रण का आमतौर पर उपयोग नहीं किया जाता है।" यूनिकोड से अक्सर पूछे जाने वाले प्रश्न: क्यू: तुर्की के लिए स्थानीय-स्वतंत्र आवरण का समर्थन करने के लिए अतिरिक्त वर्ण क्यों नहीं हैं?
JFS

1
@ jf-sebastian मैंने यह नहीं कहा कि केसफॉल्ड () दुर्व्यवहार करता है। यह सिर्फ व्यावहारिक होगा यदि यह एक वैकल्पिक पैरामीटर लागू करता है जो अपरकेस और डॉटेड अपरकेस I के विशेष उपचार को सक्षम करता है। उदाहरण के लिए, ICU लाइब्रेरी में जिस तरह से foldCase () करता है : "केस-फोल्डिंग स्थानीय-स्वतंत्र और संदर्भ नहीं है। -सेंसिटिव, लेकिन डॉटेड I और डॉटलेस I के लिए मैपिंग को शामिल करना या बाहर करना एक विकल्प है जो CaseFolding.txt में 'T' के साथ चिह्नित है। "
सर्जियोकोलनिकोव

6

मैंने इसका हल देखा रेगेक्स का उपयोग करते हुए यहां

import re
if re.search('mandy', 'Mandy Pande', re.IGNORECASE):
# is True

यह लहजे के साथ अच्छी तरह से काम करता है

In [42]: if re.search("ê","ê", re.IGNORECASE):
....:        print(1)
....:
1

हालाँकि, यह यूनिकोड वर्ण केस-असंवेदनशील के साथ काम नहीं करता है। शुक्रिया @Rhymoid को इंगित करने के लिए कि जैसा कि मेरी समझ थी कि मामले के सही होने के लिए उसे सटीक प्रतीक की आवश्यकता है। आउटपुट इस प्रकार है:

In [36]: "ß".lower()
Out[36]: 'ß'
In [37]: "ß".upper()
Out[37]: 'SS'
In [38]: "ß".upper().lower()
Out[38]: 'ss'
In [39]: if re.search("ß","ßß", re.IGNORECASE):
....:        print(1)
....:
1
In [40]: if re.search("SS","ßß", re.IGNORECASE):
....:        print(1)
....:
In [41]: if re.search("ß","SS", re.IGNORECASE):
....:        print(1)
....:

4
तथ्य यह है कि ßभीतर नहीं मिला है SSकेस-संवेदी खोज के साथ सबूत है कि यह है काम नहीं करता है यूनिकोड वर्ण के साथ काम बिल्कुल

3

सामान्य दृष्टिकोण यह है कि लकीरों और तुलनाओं के लिए उन्हें तार या निचले मामले में जोड़ दिया जाए। उदाहरण के लिए:

>>> "hello".upper() == "HELLO".upper()
True
>>> 

2

सबसे पहले लोअरकेस में कनवर्ट करने के बारे में कैसे? आप उपयोग कर सकते हैं string.lower()


4
आप उनके लोअरकेस नक्शे की तुलना नहीं कर सकते: Σίσυφοςऔर ΣΊΣΥΦΟΣबराबर परीक्षण नहीं करेंगे, लेकिन करना चाहिए।
tchrist

-2
def insenStringCompare(s1, s2):
    """ Method that takes two strings and returns True or False, based
        on if they are equal, regardless of case."""
    try:
        return s1.lower() == s2.lower()
    except AttributeError:
        print "Please only pass strings into this method."
        print "You passed a %s and %s" % (s1.__class__, s2.__class__)

3
आप एक संदेश को छोड़कर एक संदेश को stdout में प्रिंट कर रहे हैं, फिर कोई नहीं लौटाता, जो कि गलत है। यह व्यवहार में बहुत ही अनपेक्षित है।
गेरिट

-2

आपको बस इतना करना है कि दो तारों को लोअरकेस में बदलना है (सभी अक्षर लोअरकेस बन जाते हैं) और फिर उनकी तुलना करें (यह मानते हुए कि तार ASCII के तार हैं)।

उदाहरण के लिए:

string1 = "Hello World"
string2 = "hello WorlD"

if string1.lower() == string2.lower():
    print("The two strings are the same.")
else:
    print("The two strings are not the same."

यह उत्तर कोई नई जानकारी नहीं जोड़ता है। इसके अलावा, यह लगभग स्वीकृत उत्तर के समान है ।
जार्ज

-3

यह एक और रीगेक्स है, जिसे मैंने पिछले सप्ताह से प्यार करना / नफरत करना सीखा है, इसलिए आमतौर पर आयात करते हैं (इस मामले में हाँ) कुछ ऐसा जो प्रतिबिंबित करता है कि कैसे महसूस कर रहा हूँ! एक सामान्य कार्य करें .... इनपुट मांगें, फिर उपयोग करें .... कुछ = re.compile (r'foo * | स्पैम * ', Yes.I) ...... re.I (हाँ।) नीचे) IGNORECASE के समान है लेकिन आप इसे लिखने में बहुत सारी गलतियाँ नहीं कर सकते!

फिर आप अपने संदेश को रेगेक्स का उपयोग करके खोजते हैं लेकिन ईमानदारी से कहें कि यह अपने आप में कुछ पृष्ठ होना चाहिए, लेकिन मुद्दा यह है कि फू या स्पैम को एक साथ जोड़ दिया जाता है और मामले को अनदेखा कर दिया जाता है। फिर अगर या तो मिल जाते हैं तो खो_न_फाउंड उनमें से एक को प्रदर्शित करेगा। यदि नहीं तो खो_न_फाउंड कोई भी नहीं के बराबर है। यदि इसके बराबर नहीं है तो उपयोगकर्ता को लोअर केस में "रिटर्न लॉस्ट_न_फाउंड.लोवर ()" का उपयोग कर वापस लौटाएं

यह आपको बहुत अधिक आसानी से कुछ भी मैच करने की अनुमति देता है जो केस सेंसिटिव होने जा रहा है। अंत में (NCS) का अर्थ है "कोई भी गंभीरता से परवाह नहीं करता है ...!" या संवेदनशील मामला नहीं .... जो भी

अगर किसी को कोई सवाल मुझे इस पर है ..

    import re as yes

    def bar_or_spam():

        message = raw_input("\nEnter FoO for BaR or SpaM for EgGs (NCS): ") 

        message_in_coconut = yes.compile(r'foo*|spam*',  yes.I)

        lost_n_found = message_in_coconut.search(message).group()

        if lost_n_found != None:
            return lost_n_found.lower()
        else:
            print ("Make tea not love")
            return

    whatz_for_breakfast = bar_or_spam()

    if whatz_for_breakfast == foo:
        print ("BaR")

    elif whatz_for_breakfast == spam:
        print ("EgGs")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.