Skip to main content
 首页 » 编程设计

c#之解决我的正则表达式检测链接中的灾难性回溯

2024年02月25日37落叶

我有一个正则表达式来查找文本中的链接:

(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^'\"\\n\\r()<>]+|\\(([^'\"\\n\\r()<>]+|(\\([^'\"\\n\\r()<>]+\\)))*\\))+(?:\\(([^'\"\\n\\r()<>]+|(\\([^'\"\\n\\r()<>]+\\)))*\\)|[^'\"\\n\\r`!()\\[\\]{};:'.,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019])) 

但是链接中的一些 ( 导致了线程锁。在互联网上搜索我发现一些网站暗示这是一个灾难性的回溯问题。我花了一些时间来优化模式但是它不起作用。有什么想法吗?

导致问题的示例输入链接:

https://subdomain.domain.com/web/?id=-%c3%a1(%c2%81y%e2%80%9a%c3%a5d%e2%80%ba%c3%a8%c2%a7%c2%be.%c3%a9+%c2%a8 

请您参考如下方法:

您应该遵守以下原则:所有后续的相邻子模式都不能匹配字符串中的同一位置。如果你用 * 量化它们或 ? , 确保它们之前的那些强制性 模式不匹配相同的文本。否则,改造模式。或者使用 atomic groupings .

(?:https?://|www\d{0,3}[.]|[a-z0-9.-]+[.][a-z]{2,4}/) part 是一个交替,两者可以在字符串中的相同位置匹配。这是无法避免的,因此请使用原子组来防止回溯到模式中。

看[a-z0-9.-]+[.] , .存在于 + 中量化的字符类。使其更线性,替换为 [a-z0-9-]*(?:\.[a-z0-9-]*)*\. .

(?:[^'"\n\r()<>]+|\(([^'"\n\r()<>]+|(\([^'"\n\r()<>]+\)))*\))+部分是 buggy 模式:[^'"\n\r()<>]+是+再次量化,这会导致正则表达式引擎将其减少为 (?:a+)+ 的情况,经典的 CA 场景。如果您不想重新设计,请使用原子分组,尽管它似乎是匹配平衡括号的模式的一部分并且可以重写为 [^'"\n\r()<>]*(?:\((?>[^()]+|(?<o>\()|(?<-o>\)))*(?(o)(?!))\)[^'"\n\r()<>]*)* .

([^'"\n\r()<>]+|(\([^'"\n\r()<>]+\)))*部分与上面部分类似,更改(至 (?>在其中量化组和其中的单一强制模式。

固定模式是

var pattern = @"(?i)\b((?>https?://|www\d{0,3}\.|[a-z0-9-]*(?:\.[a-z0-9-]*)*\.[a-z]{2,4}/)(?>[^'""\n\r()<>]+|\((?>[^'""\n\r()<>]+|\([^'""\n\r()<>]+\))*\))+(?:\((?>[^'""\n\r()<>]+|(\([^'""\n\r()<>]+\)))*\)|[^]['""\n\r`!(){};:.,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]))"; 

参见 how it fails gracefully here .