正则表达式验证花费太长时间 c#
Posted
技术标签:
【中文标题】正则表达式验证花费太长时间 c#【英文标题】:Regex validation taking too long c# 【发布时间】:2019-10-27 00:03:47 【问题描述】:我有一个使用正则表达式进行验证的场景。
这是我需要验证的文本格式,如下所示:
有效文本
name test +company abc def +phone 3434 +vehicle test +有兴趣的yyy +invited zzz
无效文本:
name te%st +company +phone 3434 +vehicle test +有兴趣 yyy +invited zzz
规则
-
文本中不应有任何其他字符,如上面的 %。
此外,第一个单词必须跟在空格后面,然后应该有一些文本,然后是 + 号。
这是我写的正则表达式:
^(([a-z]*[A-Z]*\s?)+(\w*\s*)*\+)*$
我面临的问题是当文本有效时Regex.Match(text)
立即返回true。但是当我在文本中添加一些其他无效的字符时,它需要很长时间并且调试器永远不会返回。
【问题讨论】:
对可选模式序列进行量化的嵌套量词总是会导致灾难性的回溯。 可能是回溯问题。 文本无效时是否会发生回溯?为什么文本有效时不会花费很长时间? 它正在尝试找到仍然有效的所有量词和可选部分的单个组合。 为什么不在“+”上分割,然后对每个元素进行修剪。 【参考方案1】:无效,它需要很长时间并且调试器永远不会返回。
您要求解析器考虑太多场景,并且必须在返回之前消除所有场景;因此速度很慢。
建议
使用*
这意味着零次或多次出现 使得正则表达式解析器重新思考(回溯)关于其他 可能的匹配。
就象棋而言,实际上有数百万种可能的组合。使用*
就像说给我所有可能的动作。但是我们只想要相关的动作……正则表达式模式锻造也是如此;保持在最低限度。
使用*
,如果您确实知道会有1 个或多个项目而不是0,则更喜欢使用+
。它将回溯保持在最低限度,从而加快解析速度。
对于你的失败场景,与其尝试匹配世界,为什么不首先检查无效匹配失败?这可以通过^(?! )
模式来完成。因此,您的规则提到了找不到非字符的失败,所以把它放在第一个 ^(?!.+%)
中。也就是说,如果文本中有 %
somewhere,则匹配失败。
您的示例数据是有问题的,但是在您想要作为起点的精神中,我将从以下模式开始:
^(?!.+%)(\w+\s\w+\s\+\w+\s?)+
如果%
表示失败,那么应该有一个或多个模式(字空间字空间+
word 和可能的空间)
【讨论】:
【参考方案2】:与其尝试提出“始终有效的正则表达式”,不如改写完全不使用正则表达式的解决方案。
var text = "name test +company abc def +phone 3434 +vehicle test + interested yyy +invited zzz";
var parts = text.Split('+');
var matches = parts.All(p =>
var kvp = p.Trim().Split(' ');
if( kvp.Length != 2 )
return false;
return kvp[0].All(char.IsLetter) && kvp[1].All(char.IsLetterOrDigit);
);
虽然如果您想处理大量文本,这会导致分配过多,但否则应该很好。
【讨论】:
你的正则表达式仍然充满了灾难性的回溯。 毫无疑问,但如果不查看更多示例数据,我无法找到更好看的东西。 @TanveerBadar 我已经更新了这个问题。请看 我已根据新信息更新了答案。这应该根据您指定的规则验证文本。一旦验证通过,应该很容易将其推进以实际访问 kvp。【参考方案3】:为什么不是一个简单的解析器?拆分'+'
字符,然后评估每个短语。我假设空格之前的第一个单词是键,其余的是值。还有一个检查有效字符的正则表达式;非字母数字将引发异常。
var working = "name test +company abc def +phone 3434 +vehicle test + interested yyy +invited zzz";
if (System.Text.RegularExpressions.Regex.IsMatch(working, "[^a-zA-Z0-9 +]"))
throw new InvalidOperationException();
var values = working.Split('+').Select(x => x?.Trim() ?? string.Empty);
foreach (var phrase in values)
string left, right;
var space = phrase.IndexOf(' ');
if (space > 0)
left = phrase.Substring(0, space)?.Trim() ?? string.Empty;
right = phrase.Substring(space + 1, phrase.Length - space - 1)?.Trim() ?? string.Empty;
Console.WriteLine("left: [" + left + "], right: [" + right + "]");
控制台输出:
left: [name], right: [test]
left: [company], right: [abc def]
left: [phone], right: [3434]
left: [vehicle], right: [test]
left: [interested], right: [yyy]
left: [invited], right: [zzz]
使用无效字符运行上述代码会引发异常:
var working = "na%me test +company abc def +phone 3434 +vehicle test + interested yyy +invited zzz";
...
Operation is not valid due to the current state of the object.
【讨论】:
以上是关于正则表达式验证花费太长时间 c#的主要内容,如果未能解决你的问题,请参考以下文章
C#正则验证大全 Regex.IsMatch()正则表达式验证