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

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)
JBernardo
источник
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
DSM
источник
Было 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. Это означает, что поиск не нашел совпадения

Рональд Сонфе
источник