Как я могу проверить, содержит ли строка ЛЮБЫЕ буквы алфавита?


86

Какая реализация на чистом Python лучше всего проверяет, содержит ли строка ЛЮБЫЕ буквы из алфавита?

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

Куда string_1вернется Falseза то, что в нем нет букв алфавита, и string_2вернется Trueза то, что имеет букву.


2
Следует ли ограничиваться только английским алфавитом a / z? Следует ли учитывать «специальные» символы других алфавитов, например немецкого?
Kotch

Есть ли шанс, что вы получите юникод? Или просто римские буквы ascii?
KobeJohn

Хорошее время :) В любом случае, ответьте на этот аналогичный вопрос, если вам нужна помощь в тестировании строк с символами Юникода.
KobeJohn

1
Только английский алфавит a / z и только простые латинские буквы ascii :)
Джастин Папез

Ответы:


125

Regex должен быть быстрым:

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

1
Спасибо, JBernado, это то, чем я закончил, и он работает безупречно для того, что мне нужно делать.
Джастин Папез

36
Regex определенно кажется излишним. any(c.isalpha() for c in string_1)восхитительно питонический.
Jollywatt

5
@ Джозеф Нет, это не так. Это регулярное выражение более читабельно, чем ваше выражение. Кроме того, что isalphaдаже означает? Это будет иметь совершенно другое поведение при сравнении Python 2 с Python 3. Является ли китайский частью алфавита? Если нет, вы слепо сопоставляете его со своим генератором на Python 3 (или Python 2 для строк в Юникоде!). Если вы хотите вещий , вот это: Simple is better than complex.. И проверьте комментарий OP выше: он хочет, чтобы совпадал только латинский алфавит.
JBernardo

1
Я думаю, что ответ Джозефа отлично читается и, безусловно, быстрее, чем дополнительный импорт; плюс вам не нужно запоминать порядок аргументов в re.search
Хинтон

11
Если кому-то еще интересно, каково возвращаемое значение, вы получите Matchобъект, если есть совпадение, или Noneесли его нет. Итак, это совместимо с if re.search(...шаблоном.
Srini

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 в набор перед его тестированием? Нет, эффективнее не будет. Это гарантированно будет иметь дело со всеми символами хотя бы один раз, хотя я считаю, что функция any закоротит (остановится), когда встретит первое false.
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 будет значительно более эффективным.

Но здесь выигрывает преобразование строки в регистр и проверка регистра (то есть любой из upper (). Isupper () или lower (). 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.