web-dev-qa-db-fra.com

Insensible à la casse 'in' - Python

J'adore utiliser l'expression

if 'MICHAEL89' in USERNAMES:
    ...

USERNAMES est une liste


Existe-t-il un moyen de faire correspondre les éléments sans tenir compte de la casse ou dois-je utiliser une méthode personnalisée? Je me demandais simplement s'il était nécessaire d'écrire du code supplémentaire pour cela.

Merci à tout le monde!

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

Alternativement:

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

Ou, oui, vous pouvez créer une méthode personnalisée.

159
nmichaels

Je ferais un wrapper afin que vous puissiez être non invasif. Au minimum, par exemple ...:

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

Maintenant, if CaseInsensitively('MICHAEL89') in whatever: devrait se comporter comme il convient (que le côté droit soit une liste, un dict ou un ensemble). (Il peut être nécessaire de faire plus d'efforts pour obtenir des résultats similaires pour l'inclusion de chaînes, évitez les avertissements impliquant parfois unicode, etc.).

19
Alex Martelli

Habituellement (au moins au moins) vous façonnez votre objet pour qu'il se comporte comme vous le souhaitez. name in USERNAMES n'est pas sensible à la casse, donc USERNAMES doit changer:

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

L'avantage, c'est que cela ouvre la voie à de nombreuses améliorations, sans avoir à changer de code en dehors de la classe. Par exemple, vous pouvez changer le self.names à un ensemble pour des recherches plus rapides, ou calculez le (n.lower() for n in self.names) une seule fois et le stocker sur la classe et ainsi de suite ...

10
Jochen Ritzel

Je pense que vous devez écrire du code supplémentaire. Par exemple:

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

Dans ce cas, nous formons une nouvelle liste avec toutes les entrées de USERNAMES converties en majuscules puis comparées à cette nouvelle liste.

Mettre à jour

Comme @ viraptor , il est encore préférable d'utiliser un générateur au lieu de map. Voir @ Nathon 's réponse .

6
Manoj Govindan

Voici un moyen:

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

Pour que cela fonctionne, les deux string1 et string2 Les objets doivent être de type string.

6
User

str.casefold Est recommandé pour la correspondance de chaînes ne respectant pas la casse. La solution de @ nmichaels peut être adapté trivialement.

Utilisez soit:

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

Ou:

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

Selon le docs :

Le casage est similaire à la casse minime mais plus agressif, car il est destiné à supprimer toutes les distinctions de cas d'une chaîne. Par exemple, la lettre minuscule allemande "ß" est équivalente à "ss". Comme il est déjà en minuscule, lower() ne ferait rien à 'ß'; casefold() le convertit en "ss".

5
jpp

Vous pourriez faire

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

Mise à jour: joué un peu et pense que vous pourriez obtenir une meilleure approche de type court-circuit en utilisant

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

La fonction ifilter provient d'itertools, l'un de mes modules préférés au sein de Python. C'est plus rapide qu'un générateur mais ne crée que l'élément suivant de la liste lorsqu'il est appelé.

4
wheaties

Mes 5 (faux) centimes

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

MISE À JOUR

Ouch, totalement d'accord @jpp, je vais garder comme exemple de mauvaise pratique :(

0
GBrian