Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Вложенная группа автоматически не приводит к катастрофическому обратному отскоку. В вашем случае это связано с тем, что ваше регулярное выражение вырождается в классический пример катастрофического обратного отсчета (a*)*
.
Поскольку \s
в необязательном в ^([a-zA-Z0-9'-]+\s?)*$
, на входе без каких-либо пробелов, но имеет символы вне разрешенных list, регулярное выражение просто вырождается до ^([a-zA-Z0-9'-]+)*$
.
Вы также можете думать о расширении исходного регулярного выражения:
[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?[a-zA-Z0-9'-]+\s?...
Поскольку \s
является необязательным, мы можем удалите его:
[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+[a-zA-Z0-9'-]+...
И мы получили серию последовательных [a-zA-Z0-9'-]+
, которые будут пытаться использовать все способы распространения символов между собой и взорвать сложность.
Стандартный способ записи регулярного выражения в соответствие с token delimiter token ... delimiter token
- token (delimiter token)*
. Хотя можно переписать регулярное выражение, не повторять token
, я бы рекомендовал против него, так как это сложно сделать правильно. Чтобы избежать повторения, вы можете захотеть создать регулярное выражение путем конкатенации строк.
Следуя рецепту выше:
^[a-zA-Z0-9'-]+(\s[a-zA-Z0-9'-]+)*$
Хотя вы можете видеть повторение в повторении здесь, нет катастрофическое обратное отслеживание, поскольку регулярное выражение может расширяться только до:
[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+\s[a-zA-Z0-9'-]+...
И \s
и [a-zA-Z0-9'-]
взаимно исключают друг друга - есть только один способ сопоставления любой строки.