Как проверить, что строка содержит только буквы, цифры, символы подчеркивания и тире?

Я знаю, как это сделать, если я повторяю все символы в строке, но я ищу более элегантный метод.

10 Solutions collect form web for “Как проверить, что строка содержит только буквы, цифры, символы подчеркивания и тире?”

Регулярное выражение сделает трюк с очень маленьким кодом:

import re ... if re.match("^[A-Za-z0-9_-]*$", my_little_string): # do something here 

[Изменить] Есть еще одно решение, не упомянутое еще, и оно, по-видимому, превосходит остальных, которые даны до сих пор в большинстве случаев.

Используйте string.translate для замены всех допустимых символов в строке и посмотрите, остались ли у нас какие-то недопустимые. Это довольно быстро, так как использует основную функцию C для выполнения этой работы, при этом задействовано очень мало байт-кода python.

Очевидно, что производительность – это еще не все: для наиболее читаемых решений, вероятно, лучший подход, когда не в критическом кодовом коде, а просто для того, чтобы увидеть, как складываются решения, вот сравнение производительности всех предложенных методов. check_trans – тот, который использует метод string.translate.

Тестовый код:

 import string, re, timeit pat = re.compile('[\w-]*$') pat_inv = re.compile ('[^\w-]') allowed_chars=string.ascii_letters + string.digits + '_-' allowed_set = set(allowed_chars) trans_table = string.maketrans('','') def check_set_diff(s): return not set(s) - allowed_set def check_set_all(s): return all(x in allowed_set for x in s) def check_set_subset(s): return set(s).issubset(allowed_set) def check_re_match(s): return pat.match(s) def check_re_inverse(s): # Search for non-matching character. return not pat_inv.search(s) def check_trans(s): return not s.translate(trans_table,allowed_chars) test_long_almost_valid='a_very_long_string_that_is_mostly_valid_except_for_last_char'*99 + '!' test_long_valid='a_very_long_string_that_is_completely_valid_' * 99 test_short_valid='short_valid_string' test_short_invalid='/$%$%&' test_long_invalid='/$%$%&' * 99 test_empty='' def main(): funcs = sorted(f for f in globals() if f.startswith('check_')) tests = sorted(f for f in globals() if f.startswith('test_')) for test in tests: print "Test %-15s (length = %d):" % (test, len(globals()[test])) for func in funcs: print " %-20s : %.3f" % (func, timeit.Timer('%s(%s)' % (func, test), 'from __main__ import pat,allowed_set,%s' % ','.join(funcs+tests)).timeit(10000)) print if __name__=='__main__': main() 

Результаты моей системы:

 Test test_empty (length = 0): check_re_inverse : 0.042 check_re_match : 0.030 check_set_all : 0.027 check_set_diff : 0.029 check_set_subset : 0.029 check_trans : 0.014 Test test_long_almost_valid (length = 5941): check_re_inverse : 2.690 check_re_match : 3.037 check_set_all : 18.860 check_set_diff : 2.905 check_set_subset : 2.903 check_trans : 0.182 Test test_long_invalid (length = 594): check_re_inverse : 0.017 check_re_match : 0.015 check_set_all : 0.044 check_set_diff : 0.311 check_set_subset : 0.308 check_trans : 0.034 Test test_long_valid (length = 4356): check_re_inverse : 1.890 check_re_match : 1.010 check_set_all : 14.411 check_set_diff : 2.101 check_set_subset : 2.333 check_trans : 0.140 Test test_short_invalid (length = 6): check_re_inverse : 0.017 check_re_match : 0.019 check_set_all : 0.044 check_set_diff : 0.032 check_set_subset : 0.037 check_trans : 0.015 Test test_short_valid (length = 18): check_re_inverse : 0.125 check_re_match : 0.066 check_set_all : 0.104 check_set_diff : 0.051 check_set_subset : 0.046 check_trans : 0.017 

В большинстве случаев метод перевода выглядит лучше всего, что очень важно при длинных действительных строках, но выбивается с помощью регулярных выражений в test_long_invalid (предположительно потому, что регулярное выражение может сразу же выручить, но переводить всегда приходится сканировать всю строку). Установленные подходы, как правило, наихудшие, избиение регулярных выражений только для пустого случая строки.

Использование всех (x в разрешенном_set для x в s) хорошо работает, если оно выдается раньше, но может быть плохим, если оно должно проходить через каждый символ. isSubSet и заданные различия сопоставимы и последовательно пропорциональны длине строки независимо от данных.

Аналогичная разница между методами регулярного выражения, соответствующими всем допустимым символам, и поисками недопустимых символов. Сравнение выполняется немного лучше при проверке длинной, но полностью допустимой строки, но хуже для недопустимых символов в конце строки.

Существует множество способов достижения этой цели, некоторые из них более ясны, чем другие. Для каждого из моих примеров «True» означает, что переданная строка действительна, «False» означает, что она содержит недопустимые символы.

Прежде всего, есть наивный подход:

 import string allowed = string.letters + string.digits + '_' + '-' def check_naive(mystring): return all(c in allowed for c in mystring) 

Затем используется регулярное выражение, вы можете сделать это с помощью функции re.match (). Обратите внимание, что '-' должно быть в конце [], иначе оно будет использоваться как разделитель диапазона. Также обратите внимание на $, что означает «конец строки». В других ответах, отмеченных в этом вопросе, используется специальный класс символов «\ w», я всегда предпочитаю использовать явный диапазон классов символов с помощью [], потому что его легче понять без необходимости искать краткое справочное руководство и, дело.

 import re CHECK_RE = re.compile('[a-zA-Z0-9_-]+$') def check_re(mystring): return CHECK_RE.match(mystring) 

Другое решение отметило, что вы можете сделать обратное совпадение с регулярными выражениями, я включил это здесь. Обратите внимание, что [^ …] инвертирует класс символов, потому что используется ^:

 CHECK_INV_RE = re.compile('[^a-zA-Z0-9_-]') def check_inv_re(mystring): return not CHECK_INV_RE.search(mystring) 

Вы также можете сделать что-то сложное с объектом «set». Взгляните на этот пример, который удаляет из исходной строки все допустимые символы, оставляя нас с набором, содержащим либо a) ничего, либо b) оскорбительные символы из строки:

 def check_set(mystring): return not set(mystring) - set(allowed) 

Если бы не тире и подчеркивания, самым простым решением было бы

 my_little_string.isalnum() 

(Раздел 3.6.1 справочника библиотеки Python)

В качестве альтернативы использованию регулярного выражения вы можете сделать это в наборах:

 from sets import Set allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-') if Set(my_little_sting).issubset(allowed_chars): # your action print True 
  pat = re.compile ('[^\w-]') def onlyallowed(s): return not pat.search (s) 

Ну, вы можете попросить помощь regex, великого здесь 🙂

код:

 import re string = 'adsfg34wrtwe4r2_()' #your string that needs to be matched. regex = r'^[\w\d_()]*$' # you can also add a space in regex if u want to allow it in the string if re.match(regex,string): print 'yes' else: print 'false' 

Вывод:

 yes 

Надеюсь это поможет 🙂

Вы всегда можете использовать понимание списка и проверять результаты со всеми, это будет немного менее ресурсоемким, чем использование регулярного выражения: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])

Вот что-то, основанное на «наивном подходе» Иеруба (наивное – это его слова, а не мои!):

 import string ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-') def check(mystring): return all(c in ALLOWED for c in mystring) 

Если ALLOWED был строкой, я думаю, что c in ALLOWED будет включать итерацию над каждым символом в строке до тех пор, пока не найдет совпадение или не достигнет конца. Который, цитируя Джоэла Спольского, является чем-то вроде алгоритма Шлемиеля Живописеля .

Но тестирование на существование в наборе должно быть более эффективным или, по крайней мере, в меньшей степени зависит от количества разрешенных символов. Конечно, этот подход немного быстрее на моей машине. Это понятно, и я думаю, что для большинства случаев он достаточно эффективен (на моей медленной машине я могу проверить десятки тысяч коротких строк за долю секунды). Мне это нравится.

В действительности на моей машине регулярное выражение работает в несколько раз быстрее и так же просто, как это (возможно, проще). Так что, вероятно, это лучший путь вперед.

используйте регулярное выражение и посмотрите, соответствует ли оно!

 ([az][AZ][0-9]\_\-)* 
Python - лучший язык программирования в мире.