Comment puis-je faire une comparaison de chaînes insensible à la casse en Python?
Je voudrais encapsuler la comparaison d'une chaîne régulière à une chaîne de référentiel en utilisant de manière très simple et Pythonic. Je voudrais également avoir la possibilité de rechercher des valeurs dans un dict haché par des chaînes en utilisant des chaînes python normales.
python
comparison
case-insensitive
Kozyarchuk
la source
la source
Σίσυφος
etΣΊΣΥΦΟΣ
, alors votre approche échoue, car celles-ci sont censées être le même cas de manière insensible.'ß'.lower() == 'SS'.lower()
est faux.Comparer des chaînes de façon insensible à la casse semble trivial, mais ce n'est pas le cas. J'utiliserai Python 3, car Python 2 est sous-développé ici.
La première chose à noter est que les conversions de suppression de cas dans Unicode ne sont pas triviales. Il existe des textes pour lesquels
text.lower() != text.upper().lower()
, tels que"ß"
:Mais disons que vous vouliez comparer sans casse
"BUSSE"
et"Buße"
. Heck, vous voulez probablement aussi comparer"BUSSE"
et"BUẞE"
égaliser - c'est la nouvelle forme de capital. La méthode recommandée consiste à utilisercasefold
:N'utilisez pas seulement
lower
. Sicasefold
n'est pas disponible, faire.upper().lower()
aide (mais seulement un peu).Ensuite, vous devriez considérer les accents. Si votre rendu de police est bon, vous pensez probablement
"ê" == "ê"
- mais ce n'est pas le cas:En effet, l'accent sur ce dernier est un caractère combinatoire.
La façon la plus simple de résoudre ce problème est
unicodedata.normalize
. Vous souhaitez probablement utiliser la normalisation NFKD , mais n'hésitez pas à consulter la documentation. Alors on faitPour finir, cela s'exprime ici en fonctions:
la source
x.casefold() == y.casefold()
pour des comparaisons non sensibles à la casse (et, plus important encore,x == y
pour les casse).NFD(toCasefold(NFD(str)))
deux côtés et (D147, compatibilité) desNFKD(toCasefold(NFKD(toCasefold(NFD(X)))))
deux côtés. Il indique que l'intérieurNFD
est uniquement destiné à gérer un certain caractère d'accent grec. Je suppose que c'est tout sur les cas de bord.Utilisation de Python 2, appel
.lower()
à chaque chaîne ou objet Unicode ...... fonctionnera la plupart du temps, mais ne fonctionne pas dans les situations décrites par @tchrist .
Supposons que nous ayons un fichier appelé
unicode.txt
contenant les deux chaînesΣίσυφος
etΣΊΣΥΦΟΣ
. Avec Python 2:Le caractère Σ a deux formes minuscules, ς et σ, et
.lower()
n'aidera pas à les comparer sans tenir compte de la casse.Cependant, à partir de Python 3, les trois formulaires se résoudront en ς et l'appel de lower () sur les deux chaînes fonctionnera correctement:
Donc, si vous vous souciez des cas marginaux comme les trois sigmas en grec, utilisez Python 3.
(Pour référence, Python 2.7.3 et Python 3.3.0b1 sont indiqués dans les impressions d'interpréteur ci-dessus.)
la source
La section 3.13 de la norme Unicode définit des algorithmes de correspondance sans cas.
X.casefold() == Y.casefold()
en Python 3 implémente la "correspondance par défaut sans cas" (D144).Le casefolding ne préserve pas la normalisation des chaînes dans tous les cas et la normalisation doit donc être effectuée (
'å'
vs.'å'
). D145 introduit "l'appariement canonique sans cas":NFD()
est appelé deux fois pour les cas de bord très peu fréquents impliquant le caractère U + 0345.Exemple:
Il existe également une compatibilité de correspondance sans casse (D146) pour des cas tels que
'㎒'
(U + 3392) et "correspondance sans casse d'identifiant" pour simplifier et optimiser la correspondance sans casse des identifiants .la source
casefold()
fonction n'implémente pas le traitement de cas particulier des majuscules I et des majuscules en pointillés I comme décrit dans Propriétés de pliage de cas . Par conséquent, la comparaison peut échouer pour les mots des langues turques qui contiennent ces lettres. Par exemple,canonical_caseless('LİMANI') == canonical_caseless('limanı')
doit revenirTrue
, mais il revientFalse
. Actuellement, la seule façon de gérer cela en Python est d'écrire un wrapper de dossier ou d'utiliser une bibliothèque Unicode externe, telle que PyICU.J'ai vu cette solution ici en utilisant regex .
Il fonctionne bien avec des accents
Cependant, cela ne fonctionne pas avec les caractères unicode insensibles à la casse. Merci @Rhymoid d'avoir souligné que, si je comprends bien, il a besoin du symbole exact, pour que le cas soit vrai. La sortie est la suivante:
la source
ß
ne se trouve pas à l' intérieurSS
avec la recherche insensible à la casse est la preuve qu'il ne fonctionne pas travailler avec des caractères Unicode du tout .L'approche habituelle consiste à mettre les chaînes en majuscules ou à les mettre en minuscules pour les recherches et les comparaisons. Par exemple:
la source
Que diriez-vous de convertir en minuscules en premier? vous pouvez utiliser
string.lower()
.la source
Σίσυφος
etΣΊΣΥΦΟΣ
ne serait pas tester équivalent, mais devrait.la source
Tout ce que vous aurez à faire est de convertir les deux chaînes en minuscules (toutes les lettres deviennent minuscules), puis de les comparer (en supposant que les chaînes sont des chaînes ASCII).
Par exemple:
la source
Ceci est un autre regex que j'ai appris à aimer / détester au cours de la dernière semaine, alors importez généralement comme (dans ce cas oui) quelque chose qui reflète comment je me sens! faire une fonction normale .... demander l'entrée, puis utiliser .... quelque chose = re.compile (r'foo * | spam * ', yes.I) ...... re.I (yes.I ci-dessous) est identique à IGNORECASE mais vous ne pouvez pas faire autant d'erreurs en l'écrivant!
Vous recherchez ensuite votre message à l'aide de regex, mais honnêtement, cela devrait être quelques pages en soi, mais le fait est que foo ou spam sont pipés ensemble et que la casse est ignorée. Ensuite, si l'un ou l'autre est trouvé, lost_n_found affichera l'un d'eux. si ni l'un ni l'autre, lost_n_found est égal à None. Si ce n'est pas égal à aucun, retournez user_input en minuscules en utilisant "return lost_n_found.lower ()"
Cela vous permet de faire correspondre beaucoup plus facilement tout ce qui va être sensible à la casse. Enfin (NCS) signifie "personne ne se soucie sérieusement ...!" ou pas sensible à la casse .... selon
si quelqu'un a des questions, n'hésitez pas à me contacter.
la source