Jak mogę sprawdzić, czy ciąg zawiera JAKIEKOLWIEK litery alfabetu?

86

Jaka jest najlepsza implementacja czystego Pythona do sprawdzania, czy ciąg zawiera JAKIEKOLWIEK litery alfabetu?

string_1 = "(555).555-5555"
string_2 = "(555) 555 - 5555 ext. 5555

Gdzie string_1wróciłoby, Falsegdyby nie było w nim żadnych liter alfabetu i string_2wróciłoby, gdyby Truemiał literę.

Justin Papez
źródło
2
Czy powinno to być ograniczone tylko do angielskiego alfabetu a / z? Czy należy brać pod uwagę znaki „specjalne” z innych alfabetów, np. Niemieckiego?
Kotch
Czy jest szansa, że ​​otrzymasz Unicode? A może zwykłe rzymskie litery ascii?
KobeJohn
Niezłe wyczucie czasu :) W każdym razie, sprawdź to podobne pytanie, jeśli potrzebujesz pomocy w testowaniu ciągów znaków ze znakami Unicode.
KobeJohn
1
Ograniczone tylko do angielskiego alfabetu a / z i tylko zwykłych rzymskich liter ascii :)
Justin Papez

Odpowiedzi:

125

Regex powinien być szybkim podejściem:

re.search('[a-zA-Z]', the_string)
JBernardo
źródło
1
Dziękuję JBernado, właśnie to zrobiłem i działa bezbłędnie w tym, co muszę zrobić.
Justin Papez
36
Regex z pewnością wydaje się nieco przesadzony. any(c.isalpha() for c in string_1)jest cudownie Pythonic.
Jollywatt
5
@Joseph Nie, tak nie jest. To wyrażenie regularne jest o wiele bardziej czytelne niż twoje wyrażenie. Co to w isalphaogóle znaczy? Będzie to miało zupełnie inne zachowanie podczas porównywania Pythona 2 z Pythonem 3. Czy chiński jest częścią alfabetu? Jeśli nie, ślepo dopasowujesz go do swojego generatora w Pythonie 3 (lub Pythonie 2 w przypadku ciągów znaków Unicode!). Jeśli chcesz pythonic , to jest tutaj: Simple is better than complex.. I sprawdź komentarz OP powyżej: chce, aby dopasowano tylko alfabet łaciński.
JBernardo
1
Myślę, że odpowiedź Josepha jest doskonale czytelna i na pewno jest szybsza niż dodatkowy import; dodatkowo nie musisz pamiętać kolejności argumentów w re.search
Hinton
11
W przypadku, gdy ktoś zastanawia się, jaka jest zwracana wartość, otrzymasz Matchobiekt, jeśli istnieje dopasowanie lub Nonenie ma. Więc jest to zgodne ze if re.search(...wzorem.
Srini
78

Co powiesz na:

>>> string_1 = "(555).555-5555"
>>> string_2 = "(555) 555 - 5555 ext. 5555"
>>> any(c.isalpha() for c in string_1)
False
>>> any(c.isalpha() for c in string_2)
True
DSM
źródło
Byłby set(string_1)bardziej skuteczny?
Rik Poggi
1
@Rik. Masz na myśli konwersję string_1 do zestawu przed jego przetestowaniem? Nie, nie będzie bardziej wydajne. Gwarantuje to, że przynajmniej raz zajmie się wszystkimi znakami, podczas gdy uważam, że jakakolwiek funkcja spowoduje zwarcie (zatrzymanie), gdy napotka pierwsze fałsz.
KobeJohn
Ten kod będzie nieco powolny, ponieważ wymaga wywołania funkcji na znak. Konwersja na setmoże, ale nie musi, zmniejszyć wywołania funkcji, ale dodaje pewien narzut.
JBernardo
2
@JBernardo: timeit sugeruje, że jest o rząd wielkości wolniejszy niż skompilowany regex i zajmuje tylko około 66% więcej czasu niż nieskompilowany. To dobrze mieści się w moich granicach „Nienawidzę wyrażeń regularnych”.
DSM
1
Jasne: a jeśli użyjesz "(555) .555-5555 ext. 5555" * 1000, powrócisz do porównywalnych prędkości z powodu zwarcia. O wiele bardziej wolę pisać w Pythonie niż pisać wyrażenia regularne, które trudno mi debugować, chyba że są trywialne, i nie zamierzam rezygnować z pisania czystego Pythona, chyba że wymagają tego wymagania wydajnościowe.
DSM
27

Możesz użyć islower()na swoim ciągu, aby sprawdzić, czy zawiera małe litery (wśród innych znaków). orto z isupper()również sprawdzić, czy zawiera kilka wielkich liter:

poniżej: litery w łańcuchu: test daje wartość true

>>> z = "(555) 555 - 5555 ext. 5555"
>>> z.isupper() or z.islower()
True

poniżej: brak liter w ciągu: test daje fałsz.

>>> z= "(555).555-5555"
>>> z.isupper() or z.islower()
False
>>> 

Nie należy mylić z tym, isalpha()co powraca Truetylko wtedy, gdy wszystkie znaki są literami, co nie jest tym, czego chcesz.

Zauważ, że barm za finalizuje odpowiedź kopalni ładnie, ponieważ kopalnia nie obsługuje mieszane sprawę dobrze.

Jean-François Fabre
źródło
3
Podoba mi się, że to sprawdzi, czy ZAWIERA litery, a nie tylko, czy dane wejściowe to WSZYSTKIE litery.
Cornbeetle
@Cornbeetle tak, to naprawdę odpowiada na pytanie po tylu latach, dzięki
Jean-François Fabre
Bardzo ładny sposób na ujęcie tego. Jak to jest z wydajnością? lepiej niż regex?
pnv
nie ma żadnych pętli Pythona, więc wydajność jest dobra. Nie porównywałem z wyrażeniem regularnym, ale przypuszczam, że jest nieco szybsze, szczególnie w fazie inicjalizacji, ponieważ nie ma wyrażenia regularnego do kompilacji
Jean-François Fabre
13

Podobała mi się odpowiedź udzielona przez @ jean-françois-fabre , ale jest niekompletna.
Jego podejście zadziała, ale tylko wtedy, gdy tekst zawiera wyłącznie małe lub duże litery:

>>> text = "(555).555-5555 extA. 5555"
>>> text.islower()
False
>>> text.isupper()
False

Lepszym podejściem jest najpierw wielkie lub małe litery w ciągu, a następnie sprawdzenie.

>>> string1 = "(555).555-5555 extA. 5555"
>>> string2 = '555 (234) - 123.32   21'

>>> string1.upper().isupper()
True
>>> string2.upper().isupper()
False
Drożdże piwne
źródło
8

Możesz użyć wyrażenia regularnego w następujący sposób:

import re

print re.search('[a-zA-Z]+',string)
słabo
źródło
2

Przetestowałem każdą z powyższych metod, aby dowiedzieć się, czy w danym ciągu znajdują się jakieś alfabety i znalazłem średni czas przetwarzania na ciąg na standardowym komputerze.

~ 250 ns dla

import re

~ 3 µs dla

re.search('[a-zA-Z]', string)

~ 6 µs dla

any(c.isalpha() for c in string)

~ 850 ns dla

string.upper().isupper()


W przeciwieństwie do tego, co przypuszczano, importowanie re zajmuje niewiele czasu, a wyszukiwanie za pomocą re zajmuje około połowy czasu w porównaniu z iteracją isalpha () nawet dla stosunkowo małego ciągu.
Dlatego w przypadku większych ciągów i większej liczby zliczeń re byłby znacznie bardziej wydajny.

Ale konwersja ciągu znaków na wielkość liter i sprawdzenie wielkości liter (tj . Dowolna z właściwości upper (). Isupper () lub lower (). Islower () ) wygrywa tutaj. W każdej pętli jest znacznie szybszy niż re.search () i nie wymaga nawet dodatkowego importu.

Mihir Verma
źródło
1
Możesz również skompilować wyrażenie regularne w celu dalszej optymalizacji. alpha_regex = re.compile ('[a-zA-Z]') później alpha_regex.search (string)
Behdad Forghani
Nie wspominając o tym, że isalpha () nie sprawdza się dobrze w przypadku wielu języków. Szukałem tego, ponieważ chciałem sprawdzić, czy ciąg, który ma być koreański, zawiera jakieś angielskie litery, a metoda isalpha () zwraca True dla każdego koreańskiego ciągu.
Chan Woo,
0

Możesz to również zrobić dodatkowo

import re
string='24234ww'
val = re.search('[a-zA-Z]+',string) 
val[0].isalpha() # returns True if the variable is an alphabet
print(val[0]) # this will print the first instance of the matching value

Zauważ również, że jeśli zmienna val zwraca None. Oznacza to, że wyszukiwanie nie znalazło dopasowania

Ronald Saunfe
źródło