【问题标题】:String manipulation vs Regexps字符串操作与正则表达式
【发布时间】:2011-04-06 08:32:54
【问题描述】:

我们经常被告知正则表达式很慢,应尽可能避免使用。

但是,考虑到自己进行一些字符串操作的开销(不是在谈论算法错误 - 这是另一回事),尤其是在 PHPPerl 中(可能是 @987654323 @) 什么是limit,在这种情况下我们可以考虑字符串操作是一个更好的选择吗?哪些正则表达式特别占用 CPU?

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

正则表达式可能会更快:

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

但是呢

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

手工制作的特定算法会不会更快(同时编写时间更长)?

编辑

问题的重点是确定哪种正则表达式最好通过字符串操作专门针对给定问题重写?

edit2

一个常见的实现是 Perl 正则表达式。例如在 Perl 中 - 这需要知道它们是如何实现的 - 应该避免什么 种类 的正则表达式,因为实现会使过程变得冗长且无效?它可能不是一个复杂的正则表达式......

2011 年 7 月编辑(基于 cmets)

我并不是说所有的正则表达式都很慢。众所周知,某些特定的正则表达式模式很慢,因为它们的特定处理以及它们的实现。
例如,在最近的 Perl / PHP 实现中,已知的相当慢 - 应该避免?
已经进行了自己的研究(分析器......)并且能够提供关于建议/避免什么的一般指南的人应该会给出答案。

【问题讨论】:

  • 我会说这应该是社区 Wiki,因为它本质上是主观的(可能会更快,你会推荐什么)。

标签: java php regex perl string


【解决方案1】:

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

正则表达式在电子邮件验证等某些事情上很糟糕,因为主题太复杂,而不是因为它们很慢。 proper email validation regex 的长度超过 6,000 个字符,它甚至不能处理所有情况(您必须先去除 cmets)。

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

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

您似乎关心正则表达式与自定义算法的速度,但在您证明它是使用分析器之前,这不是一个有效的问题。以最易于维护的方式编写代码。如果一个正则表达式是明确的,那么使用一个正则表达式。如果自定义算法清晰,则使用自定义算法。如果您在分析代码后发现其中任何一个都占用了很多时间,那么请开始寻找替代方案。

【讨论】:

  • 这是问题的重点。这取决于正则表达式的编译时间 + 运行时。什么种类的正则表达式需要很长的编译时间/运行时间?
  • @ring0 对于不同的语言,甚至同一种语言的不同版本,答案都会有所不同。如果您担心性能,则必须分析您的代码。其他的都是毫无意义的猜测。
  • +1:“您似乎关心速度……但在您证明它与分析器有关之前,这不是一个有效的问题。”
  • @Dave 我并不是说所有的正则表达式都很慢。已知某些特定的正则表达式模式很慢,因为它们的特定处理以及它们的实现。例如,在最近的 Perl / PHP 实现中,什么是已知的相当慢 - 并且应该避免?已经进行了自己的研究(分析器...)并且能够提供一种关于建议/避免什么的一般指南的人会得到答案。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

    强烈建议您了解正则表达式是如何实现的,这样您就可以知道何时编写效率低下的表达式。

    【讨论】:

      【解决方案4】:

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

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

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

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

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

      【讨论】:

        【解决方案5】:

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

        简单。

        1. 确定是否需要重写任何内容。
          (肯定的答案是每 10000 个脚本中大约 1 个,大量文本解析,资源关键)
        2. 介绍可能的解决方案。
        3. 使用一个适合您解决给定问题

        至于剩下的9999个案例,不要浪费时间在这样一个小问题上,多用你喜欢的。

        每次你问自己这样的问题时,提醒自己,默认情况下,所有额外优化和超快速的代码都会在每次用户请求时逐字符解析,这是非常有用的。没有令人费解的正则表达式,没有狡猾的字符串操作,而是一个一个地挑选旧的好字符。

        【讨论】:

          【解决方案6】:

          正则表达式并不慢。但是实现可能会很慢,主要是因为每次使用时经常会对其进行解释和构建。但是好的正则表达式库允许您使用编译版本。它们的速度非常快。

          【讨论】:

            猜你喜欢
            • 2013-04-01
            • 1970-01-01
            • 2011-12-20
            • 1970-01-01
            • 1970-01-01
            • 2015-07-13
            • 2022-01-20
            • 2021-01-08
            • 1970-01-01
            相关资源
            最近更新 更多