199 votes

Insensible à la casse 'in' - Python

J'aime 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!

240voto

nmichaels Points 21955
 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.

21voto

Alex Martelli Points 330805

Je ferais un emballage pour 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 de la manière requise (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, éviter les avertissements impliquant parfois unicode , etc.).

15voto

Jochen Ritzel Points 42916

Généralement (en programmation orientée objet, au moins), vous pouvez modeler votre objet à se comporter de la façon dont vous le souhaitez. name in USERNAMES n'est pas insensible à 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

La grande chose à ce sujet est qu'il ouvre la voie pour de nombreuses améliorations, sans avoir à changer tout le code en dehors de la classe. Par exemple, vous pouvez modifier l' self.names d'un ensemble pour accélérer les recherches, ou calculer le (n.lower() for n in self.names) qu'une seule fois et de le stocker dans la classe et ainsi de suite ...

6voto

Manoj Govindan Points 24030

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 tous les bulletins de participation en USERNAMES convertis en majuscules et en le comparant à l'encontre de cette nouvelle liste.

Mise à jour

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

5voto

wheaties Points 20917

Vous pourriez faire

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

Mise à jour: joué un peu et je 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é.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X