2010-09-02 3 views
102

Mi piace usare l'espressioneCaso insensitive 'in' - Python

if 'MICHAEL89' in USERNAMES: 
    ... 

dove USERNAMES è una lista


Esiste un modo per abbinare oggetti con caso insensibilità o ho bisogno di usare un metodo personalizzato? Mi chiedo solo se è necessario scrivere un codice extra per questo.

Grazie a tutti!

risposta

122
if 'MICHAEL89' in (name.upper() for name in USERNAMES): 
    ... 

alternativa:

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

Oppure, sì, si può fare un metodo personalizzato.

+6

'se 'CaseFudge'.lower() in [x.lower() per x nella lista]' ' – fredley

+32

[...]' crea l'intera lista. '(name.upper() per il nome in USERNAMES)' creerebbe solo un generatore e una stringa necessaria alla volta - enormi risparmi di memoria se si sta facendo molto questa operazione. (ancora più risparmi, se si crea semplicemente un elenco di nomi utente minuscoli che si riutilizzano per il controllo ogni volta) – viraptor

+2

Preferisci abbassare tutti i tasti quando si costruisce il dict, per motivi di prestazioni. – Ryan

6

Penso che devi scrivere un po 'di codice in più. Ad esempio:

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

In questo caso stiamo formando una nuova lista con tutte le voci in USERNAMES convertite in maiuscole e poi confrontando contro questa nuova lista.

Aggiornamento

Come @viraptor dice, è ancora meglio utilizzare un generatore invece di map. Vedi @Nathon's answer.

+0

Oppure potresti usare la funzione 'itertools'' imap'. È molto più veloce di un generatore ma raggiunge lo stesso obiettivo. – wheaties

4

Si potrebbe fare

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

Aggiornamento: ha giocato un po 'intorno e sto pensando che si potrebbe ottenere una migliore cortocircuito approccio di tipo utilizzando

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

La funzione ifilter è da itertools, uno dei i miei moduli preferiti in Python. È più veloce di un generatore, ma crea solo il prossimo elemento della lista quando viene chiamato.

+0

Giusto per aggiungere, potrebbe essere necessario eseguire il escape del pattern, poiché potrebbe contenere caratteri come ".", "?", Che ha un significato specail in pattern di espressioni regolari. usa re.escape (raw_string) per farlo –

15

Farei un wrapper in modo da poter essere non invasivi. Come minimo, per esempio ...:

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 

Ora, if CaseInsensitively('MICHAEL89') in whatever: dovrebbe comportarsi come richiesto (se il lato destro è una lista, dict, o impostare). (Potrebbe richiedere uno sforzo maggiore per ottenere risultati simili per l'inclusione delle stringhe, evitare avvisi in alcuni casi che riguardano lo unicode, ecc.).

+3

che non funziona per dict prova se CaseInsensitively ('MICHAEL89') in {'Michael89': True}: stampa "found" –

+2

Xavier: Avresti bisogno di 'CaseInsensitively ('MICHAEL89 ') in {CaseInsensitively (' Michael89 '): True} 'per farlo funzionare, che probabilmente non rientra in" comportarsi come richiesto ". – Gabe

+0

Tanto per esserci solo 1 modo ovvio per farlo. Questo sembra pesante a meno che non venga usato molto. Detto questo, è molto semplice. – nmichaels

8

Generalmente (almeno in ordine alfabetico) si modella l'oggetto in modo che si comporti come si desidera. name in USERNAMES non è case insensitive, quindi USERNAMES deve cambiare:

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 

La cosa grandiosa di questo è che si apre il percorso per molti miglioramenti, senza dover modificare il codice al di fuori della classe. Ad esempio, è possibile modificare self.names in un set per ricerche più veloci o calcolare lo (n.lower() for n in self.names) solo una volta e memorizzarlo nella classe e così via ...

3

Ecco un modo:

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

AttributeError: l'oggetto 'list' non ha attributo 'lower' – Jeff