Как проверить имя пользователя с помощью регулярных выражений? - PullRequest
34 голосов
/ 03 августа 2009

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

Правила:

  • Имена пользователей могут состоять из строчных букв и столицы
  • Имена пользователей могут состоять из буквенно-цифровых символов. символы
  • Имена пользователей могут состоять из подчеркивания и дефисы и пробелы
  • Не может быть двух подчеркиваний, двух гипсов или два пробела подряд
  • Не может быть подчеркивания, гипса или пробел в начале или конце

Шаблон регулярного выражения:

/^[a-zA-Z0-9]+([a-zA-Z0-9](_|-| )[a-zA-Z0-9])*[a-zA-Z0-9]+$/

Ответы [ 9 ]

70 голосов
/ 03 августа 2009

Спецификации в вопросе не очень понятны, поэтому я просто предположу, что строка может содержать только буквы и цифры ASCII, с дефисами, подчеркиванием и пробелами в качестве внутренних разделителей. Основная проблема заключается в том, что первый и последний символы не являются разделителями и что в строке никогда не бывает более одного разделителя (эта часть в любом случае кажется ясной). Вот самый простой способ:

/^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$/

После сопоставления одного или нескольких буквенно-цифровых символов, , если есть разделитель, за ним должен следовать один или несколько буквенно-цифровых символов; при необходимости повторите.

Давайте посмотрим на регулярные выражения из некоторых других ответов.

/^[[:alnum:]]+(?:[-_ ]?[[:alnum:]]+)*$/

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

/^[a-zA-Z0-9]+([_\s\-]?[a-zA-Z0-9])*$/

С другой стороны, это работает только , поскольку разделитель является необязательным. После первого разделителя он может соответствовать только одному буквенно-цифровому символу за раз. Чтобы соответствовать больше, он должен повторять всю группу: нулевые разделители, за которыми следуют один алфавитно-цифровой, снова и снова. Если за вторым [a-zA-Z0-9] следовал знак плюс, он мог бы найти совпадение по гораздо более прямому маршруту.

/^[a-zA-Z0-9][a-zA-Z0-9_\s\-]*[a-zA-Z0-9](?<![_\s\-]{2,}.*)$/

При этом используется неограниченный вид сзади, что является очень редкой функцией, но вы можете использовать прогноз с тем же эффектом:

/^(?!.*[_\s-]{2,})[a-zA-Z0-9][a-zA-Z0-9_\s\-]*[a-zA-Z0-9]$/

Это выполняет, по сути, отдельный поиск двух последовательных разделителей и не дает совпадения, если находит один. В этом случае основной корпус должен только убедиться, что все символы являются буквенно-цифровыми или разделителями, причем первый и последний из них являются буквенно-цифровыми. Поскольку эти два поля обязательны, имя должно содержать не менее двух символов.

/^[a-zA-Z0-9]+([a-zA-Z0-9](_|-| )[a-zA-Z0-9])*[a-zA-Z0-9]+$/

Это ваше собственное регулярное выражение, и оно требует, чтобы строка начиналась и заканчивалась двумя буквенно-цифровыми символами, и если в строке есть два разделителя, между ними должно быть ровно два алфавитно-цифровых символа. Так что ab, ab-cd и ab-cd-ef будут совпадать, а a, a-b и a-b-c не будут.

Кроме того, как указали некоторые комментаторы, (_|-| ) в вашем регулярном выражении должно быть [-_ ]. Эта часть не является неправильной , но если у вас есть выбор между чередованием и классом символов, вы всегда должны использовать класс символов: они более эффективны, а также более читабельны.

Опять же, меня не беспокоит вопрос о том, должны ли "буквенно-цифровые" включать не-ASCII-символы или точное значение "пробела", как применять политику несмежных внутренних разделителей с регулярным выражением.

21 голосов
/ 06 июня 2016

Ваше регулярное выражение можно упростить до:

/^[a-zA-Z0-9]+([_ -]?[a-zA-Z0-9])*$/

Визуализируется с помощью Regexper :

Visualization of username validation regex.

Как видите, имя пользователя всегда должно начинаться с буквенно-цифрового символа. За специальными символами (_, , -) должен следовать буквенно-цифровой символ. Последний символ должен быть буквенно-цифровым символом.

4 голосов
/ 03 августа 2009
 ([a-zA-Z0-9](_|-| )[a-zA-Z0-9])*

- это 0 или более повторений букв, пробелов, букв.

Так что будет соответствовать

a_aa_aa_a

но не

aaaaa

Полное регулярное выражение не может соответствовать

a_aaaaaaaaa_a for example.

Давайте посмотрим назад на то, что вы хотите:

* Usernames can consist of lowercase and capitals or alphanumerica characters
* Usernames can consist of alphanumeric characters
* Usernames can consist of underscore and hyphens and spaces
* Cannot be two underscores, two hypens or two spaces in a row
* Cannot have a underscore, hypen or space at the start or end

Начало простое ... просто сопоставьте алфавит, затем (с учетом двух в правиле строки) (алфавит или пространство черты) * и снова в и алфавит.

Чтобы не допустить появления двух последовательных пространств подряд, вам, вероятно, нужно понимать lookahead / lookbehind.

Да, и в отношении другого ответа: пожалуйста, скачайте Espresso, он ДЕЙСТВИТЕЛЬНО поможет вам понять эти вещи.

3 голосов
/ 03 августа 2009

Я предлагаю написать несколько юнит-тестов, чтобы испытать Regex. Это также поможет через несколько месяцев, когда вы обнаружите проблему с Regex и вам потребуется ее обновить.

2 голосов
/ 03 августа 2009
  1. Буквенно-цифровая не просто [a-zA-Z0-9], это акцентированные, кириллические, греческие и другие буквы, которые можно использовать в имени пользователя.

  2. (_|-| ) можно заменить на [-_ ] класс символов

1 голос
/ 03 августа 2009

Использование класса символов POSIX для буквенно-цифровых символов, чтобы он работал для ударных и других иностранных буквенных символов:

/^[[:alnum:]]+([-_ ]?[[:alnum:]])*$/

Более эффективно (предотвращает захват):

/^[[:alnum:]]+(?:[-_ ]?[[:alnum:]]+)*$/

Они также предотвращают комбинации более чем одного пробела / дефиса / подчеркивания в комбинации. Из вашей спецификации не следует, является ли это желательным, но ваше собственное регулярное выражение Похоже, это то, что вы хотите.

0 голосов
/ 03 августа 2009

Похоже, это правило не будет совпадать с чем-то вроде "a_bc", "ab_c", "a_b" или "a_b_c".

Попробуйте: /^[a-zA-Z0-9]+([_\s\-]?[a-zA-Z0-9])*$/ который соответствует вышеприведенным случаям, но не любой комбинации пробелов, тире или подчеркиваний рядом друг с другом. Например: "_-" или "_" не допускаются.

0 голосов
/ 03 августа 2009

Ваше регулярное выражение не работает. Трудная часть - это проверка последовательных пробелов / дефисов. Вы могли бы использовать этот, который использует оглядку:

/^[a-zA-Z0-9][a-zA-Z0-9_\s\-]*[a-zA-Z0-9](?<![_\s\-]{2,}.*)$/
0 голосов
/ 03 августа 2009

Еще одна рекомендация для Expresso 3.0 здесь - очень проста в использовании и создании строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...