正则表达式是一项昂贵的操作吗?至少看起来

Posted

技术标签:

【中文标题】正则表达式是一项昂贵的操作吗?至少看起来【英文标题】:Is regex a costly operation? It seems atleast 【发布时间】:2016-04-13 00:14:45 【问题描述】:

我正在为字符串编写正则表达式模式。字符串是常量类型/结构。我的意思是,它看起来像(这个格式不是那么重要,看下一个例子)-

[Data Code Format]: POP N/N/N (N: object): JSON object data

这里的 N 代表一个数字或数字。 [ ] 里面是一组字符串块。但是,这种格式是不变的。

所以,我写了一个正则表达式-

\s*((?:\S+\s+)1\S+)\s*(?:\((?:.*?)\))?:\s*(\S*)\s*(\w+)

记住这个字符串示例-

%DATA-4-JSON: POP 0/1/0 (1: object): JSON object data

效果很好,但是,我在regex101.com 上看到的是成功匹配。但是,它经历了 330 个步骤来实现这一目标。

截图-

我的问题是,它需要 330 步来实现这一点(至少在我看来,我觉得它相当沉重),我想这可以使用 if-else 和其他步骤较少的比较来实现?

我的意思是,正则表达式字符串解析这么重吗?我需要解析的 10000 个字符串的 330 步会很重,对吧?

【问题讨论】:

默认情况下任何东西都只匹配一次。 “昂贵”与什么相比? 200 美元贵吗? 写得不好的正则表达式模式不仅成本高昂,而且很危险。这个有太多可以匹配空字符串的子模式。因此,回溯陷入其中并失败,然后重试并失败......这会使您的模式变得昂贵。 是的,正则表达式很昂贵,所以要明智地使用它。 @bozzmob 编写一个没有正则表达式的函数并比较两者。如果它需要快速,那么尝试几种解决方案通常是一个好主意。浏览器有分析工具(按 F12),您可以使用它来测量它。 【参考方案1】:

当您使用正则表达式时,如果您使用回溯,它们的成本可能会很高。当您使用带有可能相互匹配的后续模式的量词时(并且如果它们之间的模式可能匹配空字符串(通常用*0,x? 量词声明)),回溯可能会起到一个坏把戏在你身上。

你的正则表达式有什么不好?

一个轻微的性能问题是由不必要的非捕获组(?:\S+\s+)1 引起的。它可以写成\S+\s+,它已经减少了步数(a bit, 302 steps)。然而,最糟糕的是\S 匹配: 分隔符。因此,正则表达式引擎必须尝试许多可能的路线来匹配您预期匹配的开头。将 \S+\s+\S 替换为 [^:\s]+\s+[^:\s]+ 和 step amount will decrease to 159!

现在,来到 (?:\((?:.*?)\))? - 删除不必要的内部非捕获组会带来另一个轻微的改进 (148 steps),用否定字符类替换 .*? 会带来另一个提升 (139 steps)。

我现在就用这个​​:

\s*([^:\s]+\s+[^:\s]+)\s*(?:\([^()]*\))?:\s*(\S*)\s*(\w+)

如果最初的 \s* 是强制性的,那将是另一个增强功能,但您会有不同的匹配项。

【讨论】:

+1 以获得关于“如何优化”和“有什么问题”的清晰解释!这正是我想要的。

以上是关于正则表达式是一项昂贵的操作吗?至少看起来的主要内容,如果未能解决你的问题,请参考以下文章

需要至少两个要求的密码的正则表达式[关闭]

正则表达式 | 正则表达式学习篇

Linux Bash之正则表达式

尽管在正则表达式中使用了全局修饰符,但仅返回一项

大学时学的正则表达式,你都喂狗吃了吗?

看完就懂系列之正则表达式(值得收藏)