正则表达式验证花费太长时间 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,则匹配失败。

    一旦 #2 完成,然后只关注提供最佳情况的有效模式。

您的示例数据是有问题的,但是在您想要作为起点的精神中,我将从以下模式开始:

^(?!.+%)(\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# 中用于电子邮件验证的最佳正则表达式

C#正则验证大全 Regex.IsMatch()正则表达式验证

C#正则验证大全 Regex.IsMatch()正则表达式验证

C# 正则表达式验证器验证

C#正则表达式验证

C# - 使用正则表达式验证电话号码