Как вы также можете разрешить точку / точку (.) В этом регулярном выражении? Отредактируйте, вот как: ^ [a-zA-Z0-9 -_ \ s \.] + $
fredrik
24
[Edit] Есть еще одно решение, которое еще не упоминалось, и в большинстве случаев оно, кажется, превосходит другие, приведенные до сих пор.
Используйте 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('','')
defcheck_set_diff(s):returnnot set(s) - allowed_set
defcheck_set_all(s):return all(x in allowed_set for x in s)
defcheck_set_subset(s):return set(s).issubset(allowed_set)
defcheck_re_match(s):return pat.match(s)
defcheck_re_inverse(s):# Search for non-matching character.returnnot pat_inv.search(s)
defcheck_trans(s):returnnot 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=''defmain():
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))
printif __name__=='__main__': main()
Подход translate кажется лучшим в большинстве случаев, особенно с длинными действительными строками, но его вытесняют регулярные выражения в test_long_invalid (предположительно, потому что регулярное выражение может немедленно выйти из строя, но translate всегда должен сканировать всю строку). Подходы с наборами обычно являются худшими, превосходя регулярные выражения только для случая пустой строки.
Использование all (x в разрешенном_наборе вместо x в s) хорошо работает, если он выйдет из строя раньше, но может быть плохим, если ему придется перебирать каждый символ. isSubSet и разница наборов сопоставимы и неизменно пропорциональны длине строки независимо от данных.
Аналогичная разница между методами регулярного выражения, сопоставляющими все допустимые символы, и поиском недопустимых символов. Сопоставление выполняется немного лучше при проверке длинной, но полностью допустимой строки, но хуже при проверке недопустимых символов в конце строки.
Используйте string.ascii_lettersвместо, string.lettersесли вы не используете флаг re.LOCALE для регулярных выражений (в противном случае вы можете получить ложноположительные результаты check_trans(). Не string.maketrans()будет работать для строк Unicode.
jfs
Для Python 3 / Unicode / from __future__ import unicode_literals) используйте trans_table3 = dict((ord(char), '') for char in allowed_chars)и def check_trans(s): return not s.translate(trans_table3). Но в целом работает хуже, чем версии RE.
Hugo
14
Есть множество способов достичь этой цели, некоторые из них более понятны, чем другие. Для каждого из моих примеров «Истина» означает, что переданная строка действительна, «Ложь» означает, что она содержит недопустимые символы.
Во-первых, наивный подход:
import string
allowed = string.letters + string.digits + '_' + '-'defcheck_naive(mystring):return all(c in allowed for c in mystring)
Затем можно использовать регулярное выражение, это можно сделать с помощью re.match (). Обратите внимание, что «-» должен стоять в конце [], иначе он будет использоваться как разделитель «диапазона». Также обратите внимание на $, что означает «конец строки». В других ответах, упомянутых в этом вопросе, используется специальный класс символов '\ w', я всегда предпочитаю использовать явный диапазон классов символов с помощью [], потому что его легче понять, не просматривая краткое справочное руководство, и проще использовать специальные кейс.
import re
CHECK_RE = re.compile('[a-zA-Z0-9_-]+$')
defcheck_re(mystring):return CHECK_RE.match(mystring)
В другом решении отмечалось, что вы можете выполнять обратное сопоставление с регулярными выражениями, я включил это здесь сейчас. Обратите внимание, что [^ ...] инвертирует класс символов, потому что используется ^:
Вы также можете сделать что-нибудь хитрое с объектом «set». Взгляните на этот пример, который удаляет из исходной строки все разрешенные символы, оставляя нам набор, содержащий либо а) ничего, или б) недопустимые символы из строки:
В вашем первом тесте регулярного выражения не должно быть "[a-zA-Z0-9 _-] + $" быть "[a-zA-Z0-9 _-] * $". Пустую строку, вероятно, следует рассматривать как соответствие.
Брайан,
Используйте, string.ascii_lettersесли вы используете регулярные выражения "[a-zA-Z]".
jfs
12
Если бы не дефисы и подчеркивания, самым простым решением было бы
В качестве альтернативы использованию регулярного выражения вы можете сделать это в наборах:
from sets import Set
allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')
if Set(my_little_sting).issubset(allowed_chars):
# your actionprintTrue
import re;
re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w: Только [a-zA-Z0-9_]
Поэтому вам нужно добавить -char для выравнивания дефиса char.
+: Соответствует одному или нескольким повторениям предыдущего символа. Я думаю, вы не принимаете пустой ввод. Но если вы это сделаете, измените на *.
^: Соответствует началу строки.
$: Соответствует концу строки.
Вам понадобятся эти два специальных символа, так как вам нужно избегать следующего случая. Нежелательные символы, подобные &здесь, могут появиться между совпадающим шаблоном.
Ну, вы можете попросить помощи регулярного выражения, здесь здорово :)
код:
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'
Вы всегда можете использовать понимание списка и проверить результаты со всеми, это будет немного менее ресурсоемко, чем использование регулярного выражения: all([c in string.letters + string.digits + ["_", "-"] for c in mystring])
Пожалуйста, проверьте свой код перед публикацией. Решение, основанное на вашем неработающем ответе, которое выполняется: all (c в string.letters + string.digits + "_" вместо c в mystring)
Джеруб
2
Это будет намного более ресурсоемким, чем регулярное выражение. Он выполняет линейное сканирование для каждого символа (лучше заранее создать набор), и вы без нужды составляете список, когда понимание генератора будет более легким.
Брайан,
-1
Вот что-то, основанное на «наивном подходе» Джеруба (наивно его слова, а не мои!):
import string
ALLOWED = frozenset(string.ascii_letters + string.digits + '_' + '-')
defcheck(mystring):return all(c in ALLOWED for c in mystring)
Если бы это ALLOWEDбыла строка, я думаю, c in ALLOWEDчто потребовалось бы перебирать каждый символ в строке, пока он не нашел совпадение или не достиг конца. Что, по словам Джоэла Спольски, является чем-то вроде алгоритма Шлемиэля Художника .
Но проверка наличия в наборе должна быть более эффективной или, по крайней мере, менее зависеть от количества разрешенных символов. Конечно, на моей машине этот подход работает немного быстрее. Это ясно, и я думаю, что он работает достаточно хорошо для большинства случаев (на моей медленной машине я могу проверить десятки тысяч коротких строк за доли секунды). Мне это нравится.
ДЕЙСТВИТЕЛЬНО на моей машине регулярное выражение работает в несколько раз быстрее и так же просто (возможно, проще). Так что это, вероятно, лучший путь вперед.
Все эти символы должны быть в одном классе, иначе вы получите ложноотрицательные результаты. Также вы забыли включить маркеры начала и конца строки ... вот так, он всегда будет соответствовать, пока присутствует один допустимый символ.
Thomas
1
Это действительно будет соответствовать, даже если нет действительных символов. Соответствие нулевой длины. Кроме того, это не в питоне.
Ответы:
Регулярное выражение поможет с минимальным количеством кода:
import re ... if re.match("^[A-Za-z0-9_-]*$", my_little_string): # do something here
источник
\w
включает\d
и_
, следовательно,isvalid = re.match(r'[\w-]+$', astr)
илиisinvalid = re.search(r'[^\w-]', astr)
. Возможное наличиеlocale.setlocale
строк или строк Unicode требует дополнительного рассмотрения.isvalid = re.match(r'[\w-]*$', astr)
- допустимы пустые строки.[Edit] Есть еще одно решение, которое еще не упоминалось, и в большинстве случаев оно, кажется, превосходит другие, приведенные до сих пор.
Используйте 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
Подход translate кажется лучшим в большинстве случаев, особенно с длинными действительными строками, но его вытесняют регулярные выражения в test_long_invalid (предположительно, потому что регулярное выражение может немедленно выйти из строя, но translate всегда должен сканировать всю строку). Подходы с наборами обычно являются худшими, превосходя регулярные выражения только для случая пустой строки.
Использование all (x в разрешенном_наборе вместо x в s) хорошо работает, если он выйдет из строя раньше, но может быть плохим, если ему придется перебирать каждый символ. isSubSet и разница наборов сопоставимы и неизменно пропорциональны длине строки независимо от данных.
Аналогичная разница между методами регулярного выражения, сопоставляющими все допустимые символы, и поиском недопустимых символов. Сопоставление выполняется немного лучше при проверке длинной, но полностью допустимой строки, но хуже при проверке недопустимых символов в конце строки.
источник
string.ascii_letters
вместо,string.letters
если вы не используете флаг re.LOCALE для регулярных выражений (в противном случае вы можете получить ложноположительные результатыcheck_trans()
. Неstring.maketrans()
будет работать для строк Unicode.from __future__ import unicode_literals
) используйтеtrans_table3 = dict((ord(char), '') for char in allowed_chars)
и defcheck_trans(s): return not s.translate(trans_table3)
. Но в целом работает хуже, чем версии RE.Есть множество способов достичь этой цели, некоторые из них более понятны, чем другие. Для каждого из моих примеров «Истина» означает, что переданная строка действительна, «Ложь» означает, что она содержит недопустимые символы.
Во-первых, наивный подход:
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». Взгляните на этот пример, который удаляет из исходной строки все разрешенные символы, оставляя нам набор, содержащий либо а) ничего, или б) недопустимые символы из строки:
def check_set(mystring): return not set(mystring) - set(allowed)
источник
string.ascii_letters
если вы используете регулярные выражения "[a-zA-Z]".Если бы не дефисы и подчеркивания, самым простым решением было бы
(Раздел 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)
источник
Регулярное выражение может быть очень гибким.
import re; re.fullmatch("^[\w-]+$", target_string) # fullmatch looks also workable for python 3.4
\w
: Только[a-zA-Z0-9_]
Поэтому вам нужно добавить
-
char для выравнивания дефиса char.+
: Соответствует одному или нескольким повторениям предыдущего символа. Я думаю, вы не принимаете пустой ввод. Но если вы это сделаете, измените на*
.^
: Соответствует началу строки.$
: Соответствует концу строки.Вам понадобятся эти два специальных символа, так как вам нужно избегать следующего случая. Нежелательные символы, подобные
&
здесь, могут появиться между совпадающим шаблоном.&&&PATTERN&&PATTERN
источник
Ну, вы можете попросить помощи регулярного выражения, здесь здорово :)
код:
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'
Выход:
Надеюсь это поможет :)
источник
Вы всегда можете использовать понимание списка и проверить результаты со всеми, это будет немного менее ресурсоемко, чем использование регулярного выражения:
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
что потребовалось бы перебирать каждый символ в строке, пока он не нашел совпадение или не достиг конца. Что, по словам Джоэла Спольски, является чем-то вроде алгоритма Шлемиэля Художника .Но проверка наличия в наборе должна быть более эффективной или, по крайней мере, менее зависеть от количества разрешенных символов. Конечно, на моей машине этот подход работает немного быстрее. Это ясно, и я думаю, что он работает достаточно хорошо для большинства случаев (на моей медленной машине я могу проверить десятки тысяч коротких строк за доли секунды). Мне это нравится.
ДЕЙСТВИТЕЛЬНО на моей машине регулярное выражение работает в несколько раз быстрее и так же просто (возможно, проще). Так что это, вероятно, лучший путь вперед.
источник
используйте регулярное выражение и посмотрите, соответствует ли оно!
([a-z][A-Z][0-9]\_\-)*
источник