Groß- und Kleinschreibung wird nicht berücksichtigt.

150

Ich liebe es, den Ausdruck zu benutzen

if 'MICHAEL89' in USERNAMES:
    ...

Wo USERNAMESist eine Liste.


Gibt es eine Möglichkeit, Elemente mit Groß- und Kleinschreibung zu vergleichen, oder muss ich eine benutzerdefinierte Methode verwenden? Ich frage mich nur, ob dafür zusätzlicher Code geschrieben werden muss.

RadiantHex
quelle

Antworten:

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

Alternative:

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

Oder ja, Sie können eine benutzerdefinierte Methode erstellen.

nmichaels
quelle
8
if 'CaseFudge'.lower() in [x.lower() for x in list]
Fredley
43
[...]erstellt die gesamte Liste. (name.upper() for name in USERNAMES)würde immer nur einen Generator und einen benötigten String gleichzeitig erstellen - massive Speichereinsparungen, wenn Sie diesen Vorgang häufig ausführen. (Noch mehr Einsparungen, wenn Sie einfach eine Liste von Benutzernamen in Kleinbuchstaben erstellen, die Sie jedes Mal zur Überprüfung verwenden)
Viraptor
2
Aus Leistungsgründen ziehen Sie es vor, beim Erstellen des Diktats alle Schlüssel zu senken.
Ryan
1
Wenn [x.lower () für x in Liste] ein Listenverständnis ist, ist (name.upper () für Name in USERNAMES) ein Tupelverständnis? Oder hat es einen anderen Namen?
Otocan
1
@otocan Es ist ein Generatorausdruck.
Nmichaels
21

Ich würde einen Wrapper machen, damit Sie nicht invasiv sein können. Minimal zum Beispiel ...:

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

Jetzt if CaseInsensitively('MICHAEL89') in whatever:sollte sich wie erforderlich verhalten (ob die rechte Seite eine Liste, ein Diktat oder eine Menge ist). (Es kann mehr Aufwand erfordern, um ähnliche Ergebnisse für das Einfügen von Zeichenfolgen zu erzielen. Vermeiden Sie in einigen Fällen Warnungen unicodeusw.).

Alex Martelli
quelle
3
Das funktioniert nicht für Diktatversuche, wenn CaseInsensitively ('MICHAEL89') in {'Michael89': True}: print "found"
Xavier Combelle
2
Xavier: Das müsste CaseInsensitively('MICHAEL89') in {CaseInsensitively('Michael89'):True}funktionieren, was wahrscheinlich nicht unter "Verhalten wie erforderlich" fällt.
Gabe
Soviel dazu, dass es nur einen offensichtlichen Weg gibt, dies zu tun. Das fühlt sich schwer an, wenn es nicht viel benutzt wird. Das heißt, es ist sehr glatt.
Nmichaels
2
@Nathon, es scheint mir, dass das invasive Ändern des Containers die "fühlt sich schwer an" Operation ist. Ein völlig nicht-invasiver Wrapper: Wie viel "leichter" könnte man bekommen?! Nicht viel;-). @Xavier, RHSs, bei denen es sich um Diktate oder Sets mit Schlüsseln / Gegenständen in Groß- und Kleinschreibung handelt, benötigen ihre eigenen nicht-invasiven Wrapper (Teil der Kurzfassung etc.und Teile meiner Antwort "erfordern mehr Aufwand" ;-).
Alex Martelli
Meine Definition von schwer beinhaltet das Schreiben einer Menge Code, um etwas zu erstellen, das nur einmal verwendet wird, wo eine weniger robuste, aber viel kürzere Version ausreichen würde. Wenn dies mehrmals verwendet wird, ist es durchaus sinnvoll.
Nmichaels
12

Normalerweise (zumindest in oop) formen Sie Ihr Objekt so, dass es sich so verhält, wie Sie es möchten. name in USERNAMESist nicht unabhängig von Groß- und Kleinschreibung, USERNAMESmuss also geändert werden:

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

Das Tolle daran ist, dass es den Weg für viele Verbesserungen öffnet, ohne dass Code außerhalb der Klasse geändert werden muss. Sie können beispielsweise self.namesdas für schnellere Suchvorgänge in ein Set ändern oder das (n.lower() for n in self.names)nur einmal berechnen und in der Klasse speichern und so weiter ...

Jochen Ritzel
quelle
10

str.casefoldwird für den String-Abgleich ohne Berücksichtigung der Groß- und Kleinschreibung empfohlen. @ nmichaels Lösung kann trivial angepasst werden.

Benutze das eine oder das andere:

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

Oder:

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

Gemäß den Dokumenten :

Casefolding ähnelt dem Lowercasing, ist jedoch aggressiver, da alle Case-Unterscheidungen in einer Zeichenfolge entfernt werden sollen. Beispielsweise entspricht der deutsche Kleinbuchstabe 'ß' "ss". Da es bereits in Kleinbuchstaben geschrieben ist, lower()würde 'ß' nichts tun; casefold() konvertiert es in "ss".

jpp
quelle
8

Hier ist eine Möglichkeit:

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

Damit dies funktioniert, müssen sowohl string1als auch string2Objekte vom Typ sein string.

Benutzer
quelle
5
AttributeError: 'list' Objekt hat kein Attribut 'lower'
Jeff
@ Jeff, das liegt daran, dass eines Ihrer Elemente eine Liste ist und beide Objekte eine Zeichenfolge sein sollten. Welches Objekt ist eine Liste?
Benutzer
1
Ich würde Sie abstimmen, aber ich kann nicht, wenn Sie Ihre Antwort nicht bearbeiten. Du liegst absolut richtig.
Jeff
@ Jeff Ich habe Klarstellung hinzugefügt.
Benutzer
6

Ich denke, Sie müssen zusätzlichen Code schreiben. Beispielsweise:

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

In diesem Fall erstellen wir eine neue Liste mit allen Einträgen in USERNAMES Großbuchstaben konvertiert sind, und vergleichen sie dann mit dieser neuen Liste.

Aktualisieren

Wie @viraptor sagt, ist es sogar besser, einen Generator anstelle von zu verwenden map. Siehe @Nathon ‚s Antwort .

Manoj Govindan
quelle
Oder Sie könnten die itertoolsFunktion verwenden imap. Es ist viel schneller als ein Generator, erreicht aber das gleiche Ziel.
Wheaties
5

Du könntest es tun

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

Update: ein bisschen herumgespielt und denke, Sie könnten einen besseren Kurzschluss-Ansatz verwenden

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

Die ifilterFunktion stammt von itertools, einem meiner Lieblingsmodule in Python. Es ist schneller als ein Generator, erstellt jedoch nur bei Bedarf das nächste Element der Liste.

Wheaties
quelle
Nur um hinzuzufügen, muss das Muster möglicherweise maskiert werden, da es möglicherweise Zeichen wie ".", "?" Enthält, die in Mustern mit regulären Ausdrücken eine besondere Bedeutung haben. benutze re.escape (raw_string) um es zu tun
Iching Chang
0

Meine 5 (falschen) Cent

'a' in "" .join (['A']). lower ()

AKTUALISIEREN

Autsch, stimme vollkommen zu @jpp, ich werde als Beispiel für schlechte Praxis behalten :(

GBrian
quelle
2
Das ist falsch. Betrachten Sie 'a' in "".join(['AB']).lower()kehrt , Truewenn dies ist nicht das, was OP will.
jpp
0

Ich brauchte dies für ein Wörterbuch anstelle einer Liste. Die Jochen-Lösung war die eleganteste für diesen Fall, also habe ich sie ein wenig modifiziert:

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

Jetzt können Sie ein Wörterbuch wie dieses konvertieren USERNAMESDICT = CaseInsensitiveDict(USERNAMESDICT)und verwendenif 'MICHAEL89' in USERNAMESDICT:

Megarushing
quelle
0

Um es in einer Zeile zu haben, habe ich Folgendes getan:

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

Ich habe es allerdings nicht zeitlich getestet. Ich bin mir nicht sicher, wie schnell / effizient es ist.

MFA
quelle