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

Исключение нулевого указателя генерируется, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  1. Вызов метода экземпляра объекта null.
  2. Доступ или изменение поля объекта null.
  3. Принимая длину null, как если бы это был массив.
  4. Доступ или изменение слотов null, как если бы это был массив.
  5. Бросок null как будто это было значение Throwable.

Приложения должны бросать экземпляры этого класса, чтобы указать на другие незаконные использования объекта null.

Ссылка: http://docs.oracle.com/javase/8/docs/api/java/lang/NullPointerException.html

81
задан Hugo 5 February 2017 в 13:23
поделиться

8 ответов

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

import re

...

if re.match("^[A-Za-z0-9_-]*$", my_little_string):
    # do something here
114
ответ дан Thomas 24 November 2019 в 09:35
поделиться

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

, В первую очередь, существует наивный подход:

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_-]+ 

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

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

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

def check_set(mystring):
    return not set(mystring) - set(allowed)
) 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)

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

def check_set(mystring):
    return not set(mystring) - set(allowed)
14
ответ дан Jerub 24 November 2019 в 09:35
поделиться

[Редактирование] Там является другим решением, не упомянутым все же, и это, кажется, превосходит по характеристикам другие данных до сих пор в большинстве случаев.

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

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

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

import string, re, timeit

pat = re.compile('[\w-]* 

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

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

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

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

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

) 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

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

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

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

22
ответ дан 9 revs 24 November 2019 в 09:35
поделиться

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

my_little_string.isalnum()

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

10
ответ дан Ber 24 November 2019 в 09:35
поделиться

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

from sets import Set

allowed_chars = Set('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-')

if Set(my_little_sting).issubset(allowed_chars):
    # your action
    print True
4
ответ дан Ber 24 November 2019 в 09:35
поделиться
 pat = re.compile ('[^\w-]')

 def onlyallowed(s):
    return not pat.search (s)
3
ответ дан Javier 24 November 2019 в 09:35
поделиться

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

-1
ответ дан William Keller 24 November 2019 в 09:35
поделиться

используйте regex и посмотрите, соответствует ли он!

([a-z][A-Z][0-9]\_\-)*
-4
ответ дан Kevin Conner 24 November 2019 в 09:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: