【问题标题】:What is a good approach for replacing simple regular expressions with custom parsers?用自定义解析器替换简单正则表达式的好方法是什么?
【发布时间】:2014-11-29 01:18:20
【问题描述】:

我正在用 C# 编写一个用于一些数据处理的程序,在做了一些分析之后,我发现我使用的正则表达式是最大的瓶颈。它们占用了整个算法大约 80% 的时间,这不仅仅是解析,所以我决定改为手动解析数据。

格式相当简单,我基本上是在解析=XXX+YYY 形式的简单算术表达式,其中XXXYYY 是术语,+ 表示一组有限的运算符之一可以应用于这些条款。总是只有两个术语和一个运算符,尽管术语可以用几种不同的方式表示。

到目前为止,我的方法基本上是编写一个类似于(matchXXX)([+-*/...])(matchYYY) 的正则表达式,然后在每个操作数上应用另一个正则表达式以查看它们是什么类型。我在编写高性能解析器方面并没有太多经验。我只在 Haskell 中使用过 Parsec,它有一种非常独特的方法,并且可能需要大量工作才能实现。

那么问题来了,为这种表达式编写解析器的好方法是什么?是否有一种在大多数情况下都行之有效的通用方法?

我不是在寻找解析器生成器。我需要的是一个可以手动实现的简单解决方案。

更新:目前最慢的正则表达式是([A-Z]+\d+)([+\-*/])([A-Z]+\d+)

【问题讨论】:

  • 为什么不直接使用String.Split 方法,将有限的字符集作为分隔符传递?
  • 如果不是太复杂,您能展示一下您的正则表达式吗?
  • 如果您使用traps,正则表达式可能会变慢,但优化后它们也可能会变快。另外,不要忘记使用RegexOptions.Compiled。发布您的正则表达式,以便我们查看它是否有问题。
  • @Dmitry 如果有办法查看拆分发生在哪个字符上,我可以这样做,但是查看 API,那里似乎没有选项。
  • 如果您也需要运营商的char,请尝试使用String.IndexOfAnyString.Substring

标签: c# regex parsing


【解决方案1】:

我会尝试的第一道攻击是优化正则表达式本身。由于您的表达式结构缺少嵌套,因此可能有一个简单的优化可以显着减少引擎所花费的时间。

接下来我会尝试通过预编译表达式更好地使用正则表达式引擎,即使用Regex 的非静态方法,而不是静态方法。

这些方法都不起作用,我会选择一个简单的recursive descent parser。这些解析器是迄今为止编码最简单的,但它们为简单语言提供了良好的性能(而且您的语言绝对简单)。

【讨论】:

    【解决方案2】:

    您是否使用反向引用?如果不是 - 太好了,您可以使用更快的正则表达式引擎对其进行优化。阅读更多精彩文章:Regular Expression Matching Can Be Simple And Fast

    由于您最复杂的正则表达式不使用它,我希望其他人也是如此。下一步——你提前知道你的正则表达式,还是它们作为输入?如果是前者——预编译它们。

    我自己编写了多正则表达式引擎(我的NLT suite 的一部分),但它仍然有点新鲜——无论如何它显示了这个想法,获取你使用的所有正则表达式,编译它们,构建一个转换表,然后运行它输入。由于该表具有 all 正则表达式的转换,因此没有时间花在思考这个或那个上。用我的 MRE 替换 .Net 正则表达式后,我得到了 x2 的加速(我说过,它很新鲜 :-D)。

    【讨论】:

      猜你喜欢
      • 2011-04-11
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多