Jak mogę porównać ciąg znaków bez rozróżniania wielkości liter w Pythonie?
Chciałbym podsumować porównanie zwykłych ciągów z ciągiem repozytorium, używając bardzo prostego i Pythońskiego sposobu. Chciałbym także mieć możliwość wyszukiwania wartości w dykcie haszowanym przez ciągi znaków za pomocą zwykłych ciągów pythonowych.
python
comparison
case-insensitive
Kozyarchuk
źródło
źródło
Σίσυφος
iΣΊΣΥΦΟΣ
, oznacza to podejście się nie powiedzie, ponieważ te mają być taka sama sprawa insensitively.'ß'.lower() == 'SS'.lower()
jest fałszywy.Porównywanie ciągów znaków bez rozróżniania wielkości liter wydaje się trywialne, ale nie jest. Będę używał Python 3, ponieważ Python 2 jest tutaj słabo rozwinięty.
Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że konwersje z usuwaniem wielkości liter w Unicode nie są trywialne. Jest to tekst, dla którego
text.lower() != text.upper().lower()
, jak"ß"
:Ale powiedzmy, że chciałeś bezmyślnie porównać
"BUSSE"
i"Buße"
. Cholera, prawdopodobnie chcesz też porównać"BUSSE"
i"BUẞE"
zrównać się - to nowa forma kapitału. Zalecanym sposobem jest użyciecasefold
:Nie używaj tylko
lower
. Jeślicasefold
nie jest dostępne, robienie.upper().lower()
pomaga (ale tylko w pewnym stopniu).Następnie powinieneś rozważyć akcenty. Jeśli Twój renderer czcionek jest dobry, prawdopodobnie myślisz
"ê" == "ê"
- ale nie:Wynika to z tego, że akcent na to drugie ma charakter łączący.
Najprostszym sposobem na poradzenie sobie z tym jest
unicodedata.normalize
. Prawdopodobnie chcesz skorzystać z normalizacji NFKD , ale sprawdź dokumentację. Potem się robiAby zakończyć, tutaj jest to wyrażone w funkcjach:
źródło
x.casefold() == y.casefold()
w przypadku porównań bez rozróżniania wielkości liter (i, co ważniejsze,x == y
dla rozróżniania wielkości liter ).NFD(toCasefold(NFD(str)))
po obu stronach i (D147, zgodność)NFKD(toCasefold(NFKD(toCasefold(NFD(X)))))
po obu stronach. Stwierdza, że wnętrzeNFD
służy wyłącznie greckiemu akcentowi. Chyba chodzi o skrzynie.Używając Python 2, wywołując
.lower()
każdy ciąg znaków lub obiekt Unicode ...... będzie działać przez większość czasu, ale faktycznie nie działa w sytuacjach opisanych przez @christ .
Załóżmy, że mamy plik o nazwie
unicode.txt
zawierający dwa ciągiΣίσυφος
iΣΊΣΥΦΟΣ
. Z Python 2:Znak Σ ma dwie małe litery, ς i σ, i
.lower()
nie pomoże w porównywaniu ich bez rozróżniania wielkości liter.Jednak, począwszy od Pythona 3, wszystkie trzy formy rozstrzygną się na ς, a wywołanie lower () na obu ciągach będzie działać poprawnie:
Więc jeśli zależy Ci na przypadkach takich jak trzy sigmy w języku greckim, użyj Python 3.
(Dla porównania, Python 2.7.3 i Python 3.3.0b1 pokazano na powyższych wydrukach interpretera.)
źródło
Sekcja 3.13 standardu Unicode definiuje algorytmy dopasowania bez rozróżniania wielkości liter.
X.casefold() == Y.casefold()
w Pythonie 3 implementuje „domyślne dopasowanie bez wielkości liter” (D144).Folderowanie nie zachowuje normalizacji ciągów we wszystkich instancjach, dlatego normalizacja musi zostać wykonana (
'å'
vs.'å'
). D145 wprowadza „kanoniczne dopasowanie bez caseless”:NFD()
jest wywoływany dwukrotnie w bardzo rzadkich przypadkach krawędzi zawierających znak U + 0345.Przykład:
Istnieje również zgodność dopasowywania bez case case (D146) dla przypadków takich jak
'㎒'
(U + 3392) i „identifier caseless dopasowanie”, aby uprościć i zoptymalizować dopasowanie caseless identyfikatorów .źródło
casefold()
funkcja ta nie implementuje specjalnego traktowania wielkich liter I i kropkowanych wielkich liter I, jak opisano w Właściwości składania spraw . Dlatego porównanie może się nie powieść dla słów z języków tureckich zawierających te litery. Na przykładcanonical_caseless('LİMANI') == canonical_caseless('limanı')
musi wrócićTrue
, ale zwracaFalse
. Obecnie jedynym sposobem na poradzenie sobie z tym problemem w Pythonie jest napisanie opakowania folderów lub użycie zewnętrznej biblioteki Unicode, takiej jak PyICU.Widziałem to rozwiązanie tutaj za pomocą wyrażenia regularnego .
Działa dobrze z akcentami
Jednak nie działa ze znakami Unicode bez rozróżniania wielkości liter. Dziękuję @Rhymoid za zwrócenie uwagi, że zgodnie z moim zrozumieniem potrzebuję dokładnego symbolu, aby sprawa była prawdziwa. Dane wyjściowe są następujące:
źródło
ß
nie znajduje się w zasięguSS
ze bez uwzględniania wielkości liter wyszukiwania dowody, że to nie działa pracę z znaków Unicode w ogóle .Zwykle stosuje się pisanie wielkimi literami lub pisanie małymi literami w celu wyszukiwania i porównań. Na przykład:
źródło
Co powiesz na najpierw konwersję na małe litery? możesz użyć
string.lower()
.źródło
Σίσυφος
iΣΊΣΥΦΟΣ
nie przetestowałby odpowiednika, ale powinien.źródło
Wszystko, co musisz zrobić, to przekonwertować dwa ciągi na małe litery (wszystkie litery stają się małe), a następnie porównać je (zakładając, że ciągi są ciągami ASCII).
Na przykład:
źródło
To kolejne wyrażenie, które nauczyłem się kochać / nienawidzić w ciągu ostatniego tygodnia, więc zwykle importuj jako (w tym przypadku tak) coś, co odzwierciedla to, jak się czuję! wykonaj normalną funkcję .... zapytaj o dane wejściowe, a następnie użyj .... coś = re.compile (r'foo * | spam * ', yes.I) ...... re.I (yes.I poniżej) jest taki sam jak IGNORECASE, ale nie możesz popełnić tylu błędów, jak to pisze!
Następnie przeszukujesz swoją wiadomość za pomocą wyrażeń regularnych, ale szczerze mówiąc, powinno to być kilka osobnych stron, ale chodzi o to, że foo lub spam są połączone razem i wielkość liter jest ignorowana. Następnie, jeśli którykolwiek zostanie znaleziony, lost_n_found wyświetli jeden z nich. jeśli żadna z nich, parametr lost_n_found nie jest równy None. Jeśli nie jest równa none, zwróć user_input małymi literami, używając „return lost_n_found.lower ()”
To pozwala znacznie łatwiej dopasować wszystko, co rozróżnia małe i wielkie litery. Wreszcie (NCS) oznacza „nikt nie dba poważnie ...!” lub nie rozróżnia wielkości liter ... cokolwiek
jeśli ktoś ma jakieś pytania, napisz mi o tym ..
źródło