字符串操作与Regexps

时间:2010-08-31 15:38:28

标签: java php regex perl string

我们经常被告知Regexps很慢,应该尽可能避免。

但是,考虑到自己做一些字符串操作的开销(不是在讨论算法错误 - 这是另一回事),尤其是PHPPerl (也许Java)什么是限制,在这种情况下,我们可以认为字符串操作是更好的选择吗?什么regexp特别是CPU贪心?

例如,对于以下内容,在C++JavaPHPPerl中,您会推荐什么

正则表达式可能更快:

  • s/abc/def/g或基于... while((i=index("abc",$x)>=0) ...$y .= substr()...的解决方案?
  • s/(\d)+/N/g或扫描算法

但是

  • 电子邮件验证regexp?
  • s/((0|\w)+?[xy]*[^xy]){2,7}/u/g

手工和特定算法不会更快(写入时间更长)吗?

修改

问题的关键在于确定哪种regexp最好通过字符串操作专门针对给定问题进行重写?

EDIT2

常见的实现是Perl regexp。例如在Perl中 - 需要知道它们是如何实现的 - 要避免使用正则表达式的,因为实现会使进程冗长无效?它可能不是一个复杂的正则表达式......

编辑2011年7月(根据评论)

我并不是说所有正则表达式都很慢。一些特定的正则表达式模式已知由于它们的特殊处理以及由于它们的实现而变慢。
例如,在最近的Perl / PHP实现中,已知的是相当慢的 - 应该避免?

6 个答案:

答案 0 :(得分:9)

谁说正则表达速度很慢?至少在Perl中,它们往往是操纵字符串的首选方法。

正则表达式在电子邮件验证等方面很糟糕,因为主题过于复杂,而不是因为它们很慢。 proper email validation regex长度超过6,000个字符,甚至不处理所有情况(您必须先删除注释)。

至少在Perl 5中,如果它有一个语法,它可能不应该用一个正则表达式进行解析。

如果正则表达式已经发展到无法再轻松维护的程度(请参阅上一个电子邮件验证示例),或者性能分析显示正则表达式是代码的慢速组件,您还应该将正则表达式重写为自定义函数。

您似乎关注正则表达式与自定义算法的速度,但在您证明它与分析器一起使用之前,这不是一个有效的问题。以最易维护的方式编写代码。如果正则表达式是明确的,那么使用正则表达式。如果清除自定义算法,则使用自定义算法。如果您发现在分析代码后要么花费大量时间,那么就开始寻找替代方案。

答案 1 :(得分:7)

使用正则表达式操作文本的一个很好的功能是模式是高级和声明性的。这为实现留下了相当大的优化空间,例如分解出最长的公共前缀或使用Boyer-Moore来表示静态字符串。简洁的符号使专家更快地阅读。我立刻明白了什么

if (s/^(.)//) {
  ...
}

正在做,相比之下,index($_, 0, 1) = ""看起来很吵。

正则表达式的重要考虑因素不是下限,而是上限。它是一个强大的工具,因此人们相信它能够从XML,电子邮件地址或C ++程序中正确提取令牌,并且没有意识到需要更强大的工具,如解析器。

答案 2 :(得分:3)

对于非常特定的目的,正则表达式永远不会比手工制作的算法快。更糟糕的是,在PHP中,它们必须在第一次使用时进行编译(之后使用缓存)。

然而,它们肯定更简洁。此外,编写自定义算法通常比正则表达式慢,因为正则表达式引擎通常以更低级别的语言实现,调用函数的开销更少等。

例如,preg_replace('/a/', 'b', $string)几乎肯定比通过字符串在PHP中循环更快。但这是执行时间的一个不变的惩罚,有时正则表达式,由于回溯,可能会有更糟糕的渐近行为。

强烈建议您了解正则表达式的实现方式,以便您知道何时编写效率低下的表达式。

答案 3 :(得分:3)

一些正则表达式非常快,正则表达式和自定义解决方案之间的差异可以忽略不计(或者不值得任何人浪费时间)。

然而,正则表达式很慢的情况是excessive backtracking occurs。正则表达式从左到右解析,并且有可能以多种方式匹配文本。因此,如果它们达到引擎意识到模式不匹配您的测试字符串的点,那么它可能重新开始并尝试以另一种方式匹配。这种重复的回溯加起来并减慢了算法的速度。

通常可以重写正则表达式以更好地执行。但最终的性能是为特定任务编写自己的优化解析器。通过编写自己的解析器,您可以从左到右进行解析,同时保持内存(或状态)。如果你在程序代码中使用这种技术,你通常可以在一次通过中实现你正在寻找的效果而且没有回溯的缓慢。

我今年早些时候面临这个决定。事实上,手头的任务是在正则表达式甚至可能的外边缘。最后我决定编写自己的解析器,一个嵌入式下推自动机,这对于我试图做的事情非常有效。顺便说一句,任务是构建一些可以解析正则表达式并为它们提供类似Intellisense的代码提示的东西。

我有点讽刺的是我没有使用正则表达式来解析正则表达式,但你可以在这里阅读它背后的思想...... http://blog.regexhero.net/2010/03/code-hinting-for-regular-expressions.html

答案 4 :(得分:3)

  

什么样的正则表达式最好通过字符串操作专门针对给定问题重写?

易。

  1. 确定是否需要重写任何内容 (肯定的答案是每10000个脚本大约1个,大量文本解析,资源关键)
  2. 执行个人资料可能的解决方案。
  3. 对于给定的问题,请使用适合您的
  4. 至于剩余的9999个案例,不要浪费你的时间处理这样一个小问题,并使用你喜欢的任何东西。

    每当你问自己这样一个问题时,提醒自己默认情况下,在每个用户请求中,所有额外优化和超快速的代码都会被char解析为char非常有用。没有脑裂纹的regexps,没有狡猾的字符串操纵,但只是一个接一个的老好的挑选字符。

答案 5 :(得分:1)

正则表达并不慢。但实现可能很慢,主要是因为它经常在每次使用时再次解释和构建。但是好的regexp库允许你使用编译版本。它们非常快。