Регулярное выражение: сопоставить строку, содержащую цифры и буквы, но не строку только чисел - PullRequest
3 голосов
/ 06 августа 2009

Вопрос

Я хотел бы иметь возможность использовать одно регулярное выражение (если это возможно), чтобы требовать, чтобы строка соответствовала [A-Za-z0-9_], но не позволяла:

  • Stringsсодержит только цифры и / или символы.
  • Строки, начинающиеся или заканчивающиеся символами
  • Несколько символов рядом с друг друга

Действительный

  • test_0123
  • t0e1s2t3
  • 0123_test
  • te0_s1t23
  • t_t

Недействительно

  • t__t
  • ____
  • 01230123
  • _0123
  • _test
  • _test123
  • test_
  • test123_

Основания для Правил

Цель этого - отфильтровать имена пользователей для сайта, над которым я работаю.Я пришел к правилам по определенным причинам.

  • Имена пользователей, содержащие только цифры и / или символы, могут вызвать проблемы с маршрутизацией и поиском в базе данных.Маршрут для /users/#{id} позволяет id быть либо идентификатором пользователя, либо именем пользователя.Поэтому имена и идентификаторы не должны конфликтовать.

  • _test выглядит странно, и я не верю, что это действительный поддомен, то есть _test.example.com

  • Мне не нравится, что t__t выглядит как поддомен.т.е. t__t.example.com

Ответы [ 9 ]

8 голосов
/ 06 августа 2009

Это соответствует именно тому, что вы хотите:

/\A(?!_)(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*(?<!_)\z/i
  1. Как минимум один буквенный символ ([a-z] в середине).
  2. Не начинается и не заканчивается подчеркиванием ((?!_) и (?<!_) в начале и в конце).
  3. Может иметь любое количество цифр, букв или подчеркиваний до и после буквенного символа, но каждое подчеркивание должно быть разделено хотя бы одной цифрой или буквой (остальные).

Редактировать: На самом деле, вам, вероятно, даже не нужны предпросмотр / lookbehinds из-за того, как работает остальная часть регулярного выражения - первая ?: круглая скобка не разрешит подчеркивание до буквенно-цифрового числа, а вторая ?: круглые скобки не допускают подчеркивания, если они не начинаются с буквенно-цифровых символов:

/\A(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*\z/i

Должно работать нормально.

2 голосов
/ 06 августа 2009

А как же:

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

Не используется обратная ссылка.

Edit:

Успешен для всех ваших тестов. Совместим с ruby.

2 голосов
/ 06 августа 2009

Я уверен, что вы могли бы поместить все это в одно регулярное выражение, но это будет непросто, и я не уверен, почему настаиваю на том, чтобы это было one regex , Почему бы не использовать несколько проходов во время проверки? Если проверки проверки выполняются, когда пользователи создают новую учетную запись, на самом деле нет никаких причин пытаться втиснуть ее в одно регулярное выражение. (То есть вы будете иметь дело только с одним элементом за раз, а не с сотнями или тысячами или более. Несколько проходов по имени пользователя нормального размера должны занять очень мало времени, я думаю).

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

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

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

x !~ /[^A-Za-z0-9_]|^_|_$|__|^\d+$/
  • никаких других символов, кроме букв, цифр и _
  • не может начинаться с _
  • не может заканчиваться на _
  • не может иметь два _ подряд
  • не может быть всех цифр

Вы не можете использовать его таким образом в Rails validates_format_of, но вы можете поместить его в метод validate для класса, и я думаю, что у вас будет гораздо больше шансов понять, что вы имели в виду , месяц или год.

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

Это не блокирует "__", но оно получает остальное:

([A-Za-z]|[0-9][0-9_]*)([A-Za-z0-9]|_[A-Za-z0-9])*

А вот более длинная форма, в которой собраны все ваши правила:

([A-Za-z]|([0-9]+(_[0-9]+)*([A-Za-z|_[A-Za-z])))([A-Za-z0-9]|_[A-Za-z0-9])*

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

0 голосов
/ 07 августа 2009
/^(?![\d_]+$)[A-Za-z0-9]+(?:_[A-Za-z0-9]+)*$/

Ваш вопрос по сути такой же, как этот , с дополнительным требованием, чтобы хотя бы один из символов был буквой. Отрицательный взгляд - (?![\d_]+$) - позаботится об этой части, и его гораздо легче (и для чтения, и для записи), чем включить его в основное регулярное выражение, как пытались это сделать некоторые другие.

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

Вот, пожалуйста:

^(([a-zA-Z]([^a-zA-Z0-9]?[a-zA-Z0-9])*)|([0-9]([^a-zA-Z0-9]?[a-zA-Z0-9])*[a-zA-Z]+([^a-zA-Z0-9]?[a-zA-Z0-9])*))$

Если вы хотите ограничить символы, которые хотите принять, просто замените все [^ a-zA-Z0-9] на [], содержащие все разрешенные символы

0 голосов
/ 06 августа 2009
(?=.*[a-zA-Z].*)^[A-Za-z0-9](_?[A-Za-z0-9]+)*$

Этот работает.

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

0 голосов
/ 06 августа 2009
[A-Za-z][A-Za-z0-9_]*[A-Za-z]

Это сработает для первых двух правил (поскольку для второго правила требуется буква в начале и в конце, для него автоматически требуются буквы).

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

...