用自定义解析器替换简单正则表达式的好方法是什么?

时间:2014-11-29 01:18:21

标签: c# regex parsing

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

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

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

那么问题是,为这种表达式编写解析器的好方法是什么?在大多数情况下,是否有一种通用方法可以正常使用?

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

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

2 个答案:

答案 0 :(得分:2)

我要尝试的第一道攻击是优化正则表达式本身。由于表达式的结构缺乏嵌套,因此可能会进行简单的优化,从而显着减少引擎所需的时间。

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

在这两种方法都不奏效的情况下,我会选择一个简单的recursive descent parser。到目前为止,这些解析器是最简单的解码器,但它们为简单语言提供了良好的性能(并且您的语言绝对简单)。

答案 1 :(得分:0)

你是否使用反向引用?如果不是 - 很棒,你可以使用更快的正则表达式引擎来优化它。在这里阅读更多优秀文章:Regular Expression Matching Can Be Simple And Fast

由于你最复杂的正则表达式没有使用它,我希望其他人就是这种情况。下一步 - 你提前知道你的正则表达,还是作为输入?如果是前者 - 预先编译它们。

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