Як я можу перевірити, чи містить рядок БУДЬ-ЯКІ літери алфавіту?


86

Яка найкраща реалізація чистого Python для перевірки, чи містить рядок БУДЬ-ЯКІ літери з алфавіту?

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

Куди string_1б повернутися Falseза відсутність літер алфавіту в ньому і string_2повернувся б Trueза наявність літери.


2
Чи слід це обмежувати лише англійським a / z алфавітом? Чи слід враховувати "спеціальні" символи з інших алфавітів, таких як німецький?
Котч

Чи є шанс, що ви отримаєте Unicode? Або просто прості букви ascii римські?
KobeJohn

Хороший час там :) У будь-якому випадку, перевірте це подібне запитання, якщо вам потрібна допомога при тестуванні рядків із символами Unicode.
KobeJohn

1
Обмежено лише англійським алфавітом a / z та лише простими латинськими літерами ascii :)
Justin Papez

Відповіді:


125

Regex повинен бути швидким підходом:

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

1
Дякую JBernado, це те, що я в підсумку зробив, і це працює бездоганно для того, що мені потрібно зробити.
Джастін Папес

37
Regex, безумовно, здається трохи надмірним. any(c.isalpha() for c in string_1)смачно пітонічна.
Jollywatt

5
@ Джозеф Ні, це не так. Цей регулярний вираз набагато читабельніший, ніж ваш вираз. Крім того, що взагалі isalphaозначає? Це буде мати абсолютно різну поведінку при порівнянні Python 2 з Python 3. Чи є китайська частина алфавіту? Якщо ні, ви сліпо узгоджуєте його зі своїм генератором на Python 3 (або Python 2 для рядків Unicode!). Якщо ви хочете віщий , ось це: Simple is better than complex.. І перевірте коментар OP вище: Він хоче, щоб збігався лише римський алфавіт.
JBernardo

1
Я думаю, що відповідь Джозефа цілком читається, і це, звичайно, швидше, ніж додатковий імпорт; плюс вам не потрібно пам’ятати порядок аргументів у повторних пошуках
Хінтон,

11
Якщо хтось ще задається питанням, що таке повернене значення, ви отримуєте Matchоб’єкт, якщо є збіг або Noneякщо його немає. Отже, це сумісно з if re.search(...малюнком.
Сріні

78

Як щодо:

>>> 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

Було set(string_1)б ефективніше?
Rik Poggi

1
@Rik. Ви маєте на увазі перетворення рядка_1 в набір перед тестуванням? Ні, це не буде ефективніше. Це гарантовано матиме справу з усіма символами принаймні один раз, поки я вважаю, що будь-яка функція буде коротко замикатися (зупинятися), коли зустріне перше помилкове.
KobeJohn

Цей код буде дещо повільним, оскільки вимагає виклику функції на символ. Перетворення setможе зменшити або не знизити виклики функцій, але додає трохи накладних витрат.
JBernardo

2
@JBernardo: timeit припускає, що це приблизно на порядок повільніше, ніж скомпільований регулярний вираз, і займає лише приблизно на 66% більше часу, ніж нескладений. Це цілком відповідає моїм "Я ненавиджу регулярні вирази".
DSM

1
Звичайно: і якщо ви використовуєте "(555) .555-5555 ext. 5555" * 1000, ви повертаєтеся до порівнянних швидкостей через коротке замикання. Я набагато більше люблю писати на Python, ніж писати регулярні вирази, які мені важко налагоджувати, якщо вони не є тривіальними, і я не збираюся відмовлятися від написання чіткого Python, якщо цього не вимагають вимоги до продуктивності.
DSM

27

Ви можете використовувати islower()свій рядок, щоб перевірити, чи містить він деякі малі літери (серед інших символів). orце, isupper()щоб також перевірити, чи містить деякі великі літери:

внизу: літери в рядку: тест дає true

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

внизу: у рядку немає літер: тест дає помилку.

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

Не можна змішувати з isalpha()поверненнями Trueлише в тому випадку, якщо всі символи - букви, а це не те, що потрібно

Зверніть увагу, що Барм завершує мою, оскільки моя погано справляється зі змішаним відмінком.


3
Мені подобається, що це перевірить, чи містить він літери, а не просто перевіряє, чи вводяться ВСІ букви.
Cornbeetle,

@Cornbeetle так, такий тип дійсно відповідає на питання після всіх цих років, дякую
Жан-Франсуа Фабр

Дуже хороший спосіб це сказати. Як це з точки зору ефективності? краще, ніж регулярний вираз?
pnv

тут не задіяні петлі python, тому ефективність хороша. Я не порівнював із регулярним виразом, але, гадаю, це трохи швидше, спеціально для фази ініціалізації, тому що регулярного
Жан-Франсуа Фабр

13

Мені сподобалась відповідь, надана @ jean-françois-fabre , але вона є неповною.
Його підхід спрацює, але лише якщо текст містить суто малі чи великі літери:

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

Кращий підхід - спочатку прописати рядок у верхньому чи нижньому регістрі, а потім перевірити.

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

>>> string1.upper().isupper()
True
>>> string2.upper().isupper()
False

8

Ви можете використовувати такий регулярний вираз:

import re

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

2

Я протестував кожен із наведених вище методів, щоб з’ясувати, чи містяться в даному рядку якісь алфавіти, і з’ясував середній час обробки на рядок на стандартному комп’ютері.

~ 250 нс для

import re

~ 3 мкс для

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

~ 6 мкс для

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

~ 850 нс для

string.upper().isupper()


На відміну від передбачуваного, імпорт re займає незначний час, а пошук за допомогою re займає приблизно половину часу порівняно з ітерацією isalpha () навіть для відносно невеликого рядка.
Отже, для більших рядків і більших відліків re буде значно ефективнішим.

Але перетворення рядка у регістр і перевірка регістру (тобто будь-який з верхнього (). Isupper () або нижнього (). Islower () ) виграє тут. У кожному циклі це значно швидше, ніж re.search (), і навіть не потрібно додаткового імпорту.


1
Ви також можете скласти регулярний вираз для подальшої оптимізації. alpha_regex = re.compile ('[a-zA-Z]') пізніше alpha_regex.search (рядок)
Бехдад Форгані

Не кажучи вже про те, що isalpha () погано тренується для багатьох мов. Я шукав це, тому що хотів перевірити, чи містить рядок, котрий, як очікується, корейська, англійські літери, а метод isalpha () повертає True для кожного корейського рядка.
Чан Ву

0

Ви також можете зробити це додатково

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

Також зверніть увагу, що якщо змінна val повертає None. Це означає, що пошук не знайшов відповідності

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.