केस असंवेदनशील 'में'


151

मैं अभिव्यक्ति का उपयोग कर प्यार करता हूँ

if 'MICHAEL89' in USERNAMES:
    ...

USERNAMESसूची कहाँ है


क्या मामले की असंवेदनशीलता के साथ वस्तुओं का मिलान करने का कोई तरीका है या क्या मुझे कस्टम विधि का उपयोग करने की आवश्यकता है? बस सोच रहा था कि क्या इसके लिए अतिरिक्त कोड लिखने की आवश्यकता है।

जवाबों:


179
username = 'MICHAEL89'
if username.upper() in (name.upper() for name in USERNAMES):
    ...

वैकल्पिक रूप से:

if username.upper() in map(str.upper, USERNAMES):
    ...

या, हाँ, आप एक कस्टम विधि बना सकते हैं।


8
if 'CaseFudge'.lower() in [x.lower() for x in list]
14

44
[...]पूरी सूची बनाता है। (name.upper() for name in USERNAMES)यदि आप इस ऑपरेशन को बहुत अधिक कर रहे हैं तो केवल एक जनरेटर और एक समय में एक स्ट्रिंग की आवश्यकता होगी - बड़े पैमाने पर मेमोरी बचत। (इससे भी अधिक बचत, यदि आप लोअरकेस उपयोगकर्ता नाम की एक सूची बनाते हैं, जिसे आप हर बार जांचने के लिए पुनः प्रयोग करते हैं)
विराट

2
प्रदर्शन कारणों से, तानाशाही का निर्माण करते समय सभी कुंजियों को कम करना पसंद करें।
रयान

1
अगर [x.lower () सूची में x के लिए] एक सूची समझ है, (name.upper () USERNAMES में नाम के लिए) एक तुच्छ समझ है? या इसका कोई और नाम है?
ओटोकन

1
@otocan यह एक जनरेटर अभिव्यक्ति है।
नौचमैल

21

मैं एक आवरण बनाऊंगा ताकि आप गैर-आक्रामक हो सकें। उदाहरण के लिए, न्यूनतम ...:

class CaseInsensitively(object):
    def __init__(self, s):
        self.__s = s.lower()
    def __hash__(self):
        return hash(self.__s)
    def __eq__(self, other):
        # ensure proper comparison between instances of this class
        try:
           other = other.__s
        except (TypeError, AttributeError):
          try:
             other = other.lower()
          except:
             pass
        return self.__s == other

अब, if CaseInsensitively('MICHAEL89') in whatever:आवश्यकता के अनुसार व्यवहार करना चाहिए (चाहे दाहिने हाथ की ओर एक सूची हो, तानाशाह या सेट)। (इसमें स्ट्रिंग समावेशन के लिए समान परिणाम प्राप्त करने के लिए अधिक प्रयास की आवश्यकता हो सकती है, कुछ मामलों में चेतावनी से बचना unicode, आदि)।


3
अगर {@ Michael89 ’: CaseInsensitively (EL MICHAEL89’) में {तानाशाह: सच}: प्रिंट "पाया"
Xavier Combelle

2
ज़ेवियर: आपको इसके CaseInsensitively('MICHAEL89') in {CaseInsensitively('Michael89'):True}लिए काम करने की ज़रूरत होगी , जो संभवतः "व्यवहार के अनुसार आवश्यक नहीं है"।
गाबे

ऐसा करने के लिए केवल 1 स्पष्ट तरीका है। यह तब तक भारी लगता है जब तक कि इसका भरपूर उपयोग न हो। यह कहा, यह बहुत चिकनी है।
17

2
@ नाथन, मुझे ऐसा लगता है कि कंटेनर को आक्रामक रूप से बदलने के लिए "भारी लगता है" ऑपरेशन है। एक पूरी तरह से गैर इनवेसिव आवरण: यह कितना "हल्का" हो सकता है? बहुत ज्यादा नहीं;-)। @Xavier, RHS की मिक्स्ड केस कीज़ / आइटम के साथ dicts या सेट हैं, उन्हें अपने स्वयं के गैर-इनवेसिव रैपर (संक्षिप्त का भाग etc.और "अधिक प्रयास की आवश्यकता है";
एलेक्स मार्टेली

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

12

आमतौर पर (उफ़ में कम से कम) आप अपनी इच्छानुसार व्यवहार करने के लिए अपनी वस्तु को आकार देते हैं। name in USERNAMESअसंवेदनशील नहीं है, इसलिए USERNAMESबदलने की जरूरत है:

class NameList(object):
    def __init__(self, names):
        self.names = names

    def __contains__(self, name): # implements `in`
        return name.lower() in (n.lower() for n in self.names)

    def add(self, name):
        self.names.append(name)

# now this works
usernames = NameList(USERNAMES)
print someone in usernames

इसके बारे में महान बात यह है कि यह कई सुधारों के लिए मार्ग खोलता है, बिना किसी कोड को कक्षा के बाहर बदलने के लिए। उदाहरण के लिए, आप self.namesतेजी से लुकअप के लिए सेट में बदलाव कर सकते हैं , या (n.lower() for n in self.names)केवल एक बार गणना कर सकते हैं और इसे क्लास वगैरह पर स्टोर कर सकते हैं ...


10

str.casefoldकेस-असंवेदनशील स्ट्रिंग मिलान के लिए अनुशंसित है। @ nmichaels का समाधान तुच्छ रूप से अनुकूलित किया जा सकता है।

या तो उपयोग करें:

if 'MICHAEL89'.casefold() in (name.casefold() for name in USERNAMES):

या:

if 'MICHAEL89'.casefold() in map(str.casefold, USERNAMES):

डॉक्स के अनुसार :

Casefolding लोअरकेसिंग के समान है लेकिन अधिक आक्रामक है क्योंकि यह एक स्ट्रिंग में सभी मामले के अंतर को हटाने का इरादा है। उदाहरण के लिए, जर्मन लोअरकेस अक्षर 'ß' "ss" के बराबर है। चूंकि यह पहले से ही छोटा है, इसलिए lower()'case' के लिए कुछ नहीं करेगा; casefold() इसे "ss" में कनवर्ट करता है।


8

यहाँ एक तरीका है:

if string1.lower() in string2.lower(): 
    ...

यह काम करने के लिए, दोनों प्रकार string1और string2ऑब्जेक्ट प्रकार के होने चाहिए string


5
गुण: 'सूची' ऑब्जेक्ट में कोई विशेषता नहीं है 'निचला'
जेफ

@Jeff ऐसा इसलिए है क्योंकि आपका एक तत्व एक सूची है, और दोनों वस्तुओं को एक स्ट्रिंग होना चाहिए। कौन सी वस्तु एक सूची है?
यूजर

1
मैं आपको वोट दूंगा, लेकिन जब तक आप अपना जवाब संपादित नहीं करते, मैं नहीं कर सकता। तुम पूरी तरह ठीक हो।
जेफ

@ जेफ मैंने स्पष्टीकरण जोड़ा।
यूजर

6

मुझे लगता है कि आपको कुछ अतिरिक्त कोड लिखना होगा। उदाहरण के लिए:

if 'MICHAEL89' in map(lambda name: name.upper(), USERNAMES):
   ...

इस मामले में हम सभी प्रविष्टियों के साथ एक नई सूची बना रहे हैं, USERNAMESजिसे ऊपरी मामले में परिवर्तित किया गया है और फिर इस नई सूची के खिलाफ तुलना की जा रही है।

अपडेट करें

जैसा @viraptor कहते हैं, इसके बजाय एक जनरेटर का उपयोग करना और भी बेहतर है map@ नाथन का जवाब देखें ।


या आप itertoolsफ़ंक्शन का उपयोग कर सकते हैं imap। यह एक जनरेटर की तुलना में बहुत तेज़ है लेकिन समान लक्ष्य को पूरा करता है।
गेहूं 24

5

तुम यह कर सकते थे

matcher = re.compile('MICHAEL89', re.IGNORECASE)
filter(matcher.match, USERNAMES) 

अद्यतन: एक बिट के आसपास खेला जाता है और सोच रहा था कि आप एक बेहतर शॉर्ट-सर्किट प्रकार का उपयोग कर सकते हैं

matcher = re.compile('MICHAEL89', re.IGNORECASE)
if any( ifilter( matcher.match, USERNAMES ) ):
    #your code here

ifilterसमारोह, पायथन के भीतर मेरी पसंदीदा मॉड्यूल में से एक itertools से है। यह एक जनरेटर से तेज है, लेकिन केवल सूची का अगला आइटम बनाता है जब इसे बुलाया जाता है।


बस जोड़ने के लिए, पैटर्न से बचने की आवश्यकता हो सकती है, क्योंकि इसमें ",", "," जैसे वर्ण शामिल हो सकते हैं, जिसका नियमित अभिव्यक्ति पैटर्न में विशिष्ट अर्थ है। यह करने के लिए re.escape (raw_string) का उपयोग करें
इचिंग चांग

0

मेरा 5 (गलत) सेंट

"a" in "" .join (['A'])। निचला ()

अपडेट करें

आउच, पूरी तरह से @jpp से सहमत हैं, मैं बुरे अभ्यास के उदाहरण के रूप में रखूँगा :(


2
ये गलत है। जब ओपी चाहता है तो 'a' in "".join(['AB']).lower()रिटर्न पर विचार करें True
जेपी

0

मुझे सूची के बजाय एक शब्दकोश के लिए इसकी आवश्यकता थी, जोचेन समाधान उस मामले के लिए सबसे सुरुचिपूर्ण था, इसलिए मैंने इसे थोड़ा संशोधित किया:

class CaseInsensitiveDict(dict):
    ''' requests special dicts are case insensitive when using the in operator,
     this implements a similar behaviour'''
    def __contains__(self, name): # implements `in`
        return name.casefold() in (n.casefold() for n in self.keys())

अब आप जैसे शब्दकोश USERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT)का उपयोग कर सकते हैं और उपयोग कर सकते हैंif 'MICHAEL89' in USERNAMESDICT:


0

इसे एक पंक्ति में रखने के लिए, मैंने यही किया है:

if any(([True if 'MICHAEL89' in username.upper() else False for username in USERNAMES])):
    print('username exists in list')

मैंने इसे समय-वार परीक्षण नहीं किया था। मुझे यकीन नहीं है कि यह कितना तेज / कुशल है।

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