2010-03-24 76 views
1

我想正则表达式来有效的输入匹配到Tags输入字段具有以下属性:如何改善此正则表达式?

  • 1-5标签
  • 每个标签长
  • 有效的标签字符是1-30个字符[ A-ZA-Z0-9-]
  • 输入和标签可以通过空白

的任何量例如被分离:

有效期:标签1标签2标签3,用破折号TAG4与 - 更多的破折号tAaG5与 - 混合大小写

这里是我迄今为止 - 它似乎工作,但我很感兴趣怎么可以简化或者如果它有任何重大缺陷:

\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。任何建议,将不胜感激,谢谢!

回答

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个标签,因为它应该。这意味着这是一个更具前瞻性的正则表达式,具有更少的回溯,更好的性能和更少的冗余。

UPDATE#3:

我在我的方式看到错误。这应该会更好。

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

刚刚过去)之前把\b将断言单词边界。这允许1-30字符长度规则再次正常工作。

+0

这是一个整洁的网站 - 感谢参考 – 2010-03-24 22:56:53

+0

@Michael - 不客气。并检查我的第二次尝试在这里。它更简单,我认为表现与你的第一个表达大致相同。 – 2010-03-24 23:12:37

+1

@Steve:我感谢你的额外努力 - 不幸的是,最新的正则表达式并不限制在30个字符/每个 - 即。它匹配一个40char标签 – 2010-03-24 23:15:26

1

你的RE看起来像是在做你正在做的事情。我可能会推荐使用而不是,但在这种情况下,只需将空白处的输入拆分为数组,然后单独验证数组中的每个值。

RE比较凉爽,但有时,他们不是来完成这项工作:)

+0

我听到你 - 在服务器上,这是我可能最终做的事情。但是,将正则表达式插入到ASP.NET MVC模型验证引擎中非常简单,我现在想要坚持使用它 – 2010-03-24 22:27:39

+0

或者您可以编写自定义验证来完成分割。 – 2010-03-24 22:30:37

0

\w可能取代a-zA-Z0-9最好的方式,但它也包含_如果这是好的。

您可能还可以打破它多一点这样的:

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

如果你总是保证有空格分隔的标签。

+2

虽然这不符合60,90,120个字符的单个标签吗? – 2010-03-24 22:31:27

+0

是的,你是对的,迈克尔,这不符合你的要求。 – Pindatjuh 2010-03-24 22:34:41

+0

是的,这就是我不清楚的是,标签是否总会被ws分开。如果不是,我不确定如何确定如何处理60个字符的长字符串?也许发布一个例子会有所帮助。 – 2010-03-24 22:36:55

0

你可以缩短到像

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

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

+0

这是不是会匹配60,90,120个字符的单个标签? – 2010-03-24 22:34:03

+0

此正则表达式不起作用。由于'\ s'处的'*','{1,30}'字段失败。 – Pindatjuh 2010-03-24 22:35:25

+0

非常真实。 :( – Ben 2010-03-24 22:43:01

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*$ 
+0

+1对于很好的解释与评论 - 我刚刚了解到一些关于组跟踪提示。我认为你仍然需要处理破折号( - ),但... – 2010-03-24 22:36:46

+0

谢谢,下次我会复制和粘贴,而不是retype。更正的错字 – Pindatjuh 2010-03-24 22:38:03

+0

我喜欢这个 - 谢谢 - 不幸的是,我无法预处理输入,例如增加一个空格 – 2010-03-24 22:43:37

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)内联修饰符语法,所以不可能使用不区分大小写的验证器正则表达式。如果我误解了这一点,我希望有人会纠正我。