我怎样才能改进这个正则表达式?

时间:2010-03-24 22:22:50

标签: javascript regex

我希望正则表达式将有效输入与Tags输入字段匹配,并具有以下属性:

  • 1-5个标签
  • 每个标签长度为1-30个字符
  • 有效标记字符为[a-zA-Z0-9 - ]
  • 输入和标签可以用任意数量的空格分隔

例如:

  

有效: tag1 tag2 tag3-with-dashes tag4-with-more-dashes 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 个答案:

答案 0 :(得分:3)

您可以将其简化为:

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

(?: )语法是一个非捕获组,我相信当你不需要组本身时,它应该可以提高性能。

然后诀窍是这句话:

(?:^|\s+)

感谢插入符号,这将匹配行的开头或空格中的一个或多个字符。

更新:这在我的测试中非常有效,而且冗余代码肯定更少。但是,我只是使用benchmarking in Regex Hero来查找原始正则表达式实际上更快。这可能是因为我的导致更多的回溯发生。

更新#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个字符长度规则再次正常工作。

答案 1 :(得分:2)

在性能方面,您可以通过以下方式优化(改进):

^(?:\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*$

答案 2 :(得分:1)

您的RE看起来几乎完全符合您的要求。我可能会建议使用RE,在这种情况下 - 只需将空格上的输入拆分成数组,然后自己验证数组中的每个值。

RE很酷,但有时,它们不是完成工作的最佳方式:)

答案 3 :(得分:0)

\w可以替换a-zA-Z0-9,但如果可以的话,它还包含_。

您也可以将其分解为更多:

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

如果您始终保证将空格分隔您的标记。

答案 4 :(得分:0)

您可以将其缩短为类似

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

我总是喜欢让我的正则表达式更简洁(它不会影响性能)。

答案 5 :(得分:0)

你不会改进。你为减少长度所做的任何事情也会使阅读变得更难,正则表达式在这方面不需要任何帮助。 ;)

那就是说,无论如何,你的正则表达式需要更加复杂。如上所述,它无法确保标记名称不以连字符开头或结尾,或包含两个或多个连续连字符。单个标记的正则表达式需要像这样构造:

[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)内联修饰符语法,因此不能使用不区分大小写的验证程序正则表达式。如果我弄错了,我希望有人会纠正我。