Как я могу улучшить это регулярное выражение? - PullRequest
1 голос
/ 25 марта 2010

Я хочу, чтобы регулярное выражение совпадало с допустимым вводом в поле ввода Tags со следующими свойствами:

  • 1-5 тегов
  • Каждый тег длиной 1-30 символов
  • Допустимые символы тега: [a-zA-Z0-9 -]
  • входные данные и теги могут быть разделены любым количеством пробелов

Например:

Действительный: tag1 tag2 с меткой-тире tag4-с-тире-тире tAaG5-with-MIXED-case

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

\s*[a-zA-Z0-9-]{1,30}(\s+[a-zA-Z0-9-]{1,30}){0,4}\s*

// that is: 
\s*                          // match all beginning whitespace
[a-zA-Z0-9-]{1,30}           // match the first tag
(\s+[a-zA-Z0-9-]{1,30}){0,4} // match all subsequent tags
\s*                          // match all ending whitespace

Предварительная обработка ввода для облегчения проблемы пробелов не возможна (например, обрезка или добавление пробела).

Если это имеет значение, это будет использоваться в javascript. Любые предложения будут оценены, спасибо!

Ответы [ 6 ]

3 голосов
/ 25 марта 2010

Вы можете упростить это немного следующим образом:

^(?:(?:^|\s+)[a-zA-Z0-9-]{1,30}){1,5}\s*$

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

Тогда уловка заключается в следующем утверждении:

(?:^|\s+)

Благодаря каретке это будет соответствовать началу строки или одному или нескольким символам пробела.

ОБНОВЛЕНИЕ: Это отлично работает в моем тестировании, и там, конечно, меньше избыточного кода.Тем не менее, я просто использовал бенчмаркинг в Regex Hero , чтобы обнаружить, что ваш оригинальный regex на самом деле быстрее.Вероятно, это связано с тем, что из-за того, что у меня происходит еще большее возвращение назад,

ОБНОВЛЕНИЕ № 2: Я нашел другой способ, который выполняет то же самое, я думаю:

^(?:\s*[a-zA-Z0-9-]{1,30}){1,5}\s*$

Я понял, что тоже пыталсяжесткий.\s* соответствует 0 или более пробелам, что означает, что он будет работать для одного тега.Но ... это будет работать и для 2-5 тегов, потому что пробел не в вашем классе персонажей [ ].И действительно, он терпит неудачу с 6 тегами, как и должно быть.Это означает, что это гораздо более дальновидное регулярное выражение с меньшим количеством обратных возвратов, лучшей производительностью и меньшей избыточностью.

ОБНОВЛЕНИЕ № 3:

Я вижу ошибку своими путями.Это должно работать лучше.

^(?:\s*[a-zA-Z0-9-]{1,30}\b){1,5}\s*$

Помещение \b непосредственно перед последним ) установит границу слова.Это позволяет правилу длины 1-30 символов снова работать правильно.

2 голосов
/ 25 марта 2010

С точки зрения производительности, вы можете оптимизировать (улучшить) это следующим образом:

^(?:\s+[a-zA-Z0-9]{1,30}){1,5}\s*$

И добавьте пробел в начале, перед тестированием регулярного выражения.

^
(?: // don't keep track of groups
\s+ // first (necessairy whitespace) or between
  [a-zA-Z0-9-]{1,30} // unchanged
  ){1,5} // 1 to 5 tags
\s*$
1 голос
/ 25 марта 2010

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

RE это круто, но иногда они не лучший способ выполнить работу:)

0 голосов
/ 25 марта 2010

Вы не собираетесь улучшать это. Все, что вы делаете для уменьшения длины, также затруднит чтение, и регулярные выражения в этом отношении не нуждаются. ;)

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

[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*

Тогда базовое регулярное выражение для совпадения с пятью тегами будет

[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*(?:\s+[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*){0,4}

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

/^\s*
 (?=[A-Za-z0-9-]{1,30}(\s+[A-Za-z0-9-]{1,30}){0,4}\s*$)
 (?:[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*\s*)+$
/

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

Я мог бы немного сократить регулярное выражение, исключив a-z из классов символов и добавив модификатор i. Я этого не делал, потому что вы говорили об использовании регулярных выражений в валидаторе ASP.NET, и, насколько я знаю, они не позволяют использовать модификаторы регулярных выражений. А поскольку JavaScript не поддерживает встроенный синтаксис (?i), регистрозависимые регулярные выражения валидатора невозможны. Если я ошибаюсь по этому поводу, надеюсь, кто-нибудь меня поправит.

0 голосов
/ 25 марта 2010

Вы можете сократить его до что-то вроде

([a-zA-Z0-9-]{1,30}\s*){1,5}

Мне всегда нравится делать свои регулярные выражения более краткими (где это не влияет на производительность).

0 голосов
/ 25 марта 2010

\w может заменить a-zA-Z0-9, но также содержит _, если все в порядке.

Вы также можете разбить его немного так:

(\s*[a-zA-Z0-9-]{1,30}){0,5}

, если вам всегда гарантировано наличие пробелов, разделяющих ваши теги.

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