C#Regex性能非常慢

时间:2016-09-13 12:47:54

标签: c# regex

我是正则表达式主题的新手。我想用以下正则表达式解析日志文件:

(?<time>(.*?))[|](?<placeholder4>(.*?))[|](?<source>(.*?))[|](?<level>[1-3])[|](?<message>(.*?))[|][|][|](?<placeholder1>(.*?))[|][|](?<placeholder2>(.*?))[|](?<placeholder3>(.*))

日志行如下所示:

2001.07.13 09:40:20|1|SomeSection|3|====== Some log message::Type: test=sdfsdf|||.\SomeFile.cpp||60|-1

带有appr的日志文件。 3000行需要很长时间才能解析它。你有一些提示来加速表现吗?谢谢......

更新 我使用正则表达式,因为我使用不同的日志文件,这些文件没有相同的结构,我就这样使用它:

string[] fileContent = File.ReadAllLines(filePath);
Regex pattern = new Regex(LogFormat.GetLineRegex(logFileFormat));

foreach (var line in fileContent)
{
   // Split log line
   Match match = pattern.Match(line);

   string logDate = match.Groups["time"].Value.Trim();
   string logLevel = match.Groups["level"].Value.Trim();
   // And so on...
}

解决方案:
谢谢你的帮助。我用以下结果测试了它:

1.)只添加了RegexOptions.Compiled:
从00:01:10.9611143 到00:00:38.8928387

2.)使用Thomas Ayoub正则表达式 从00:00:38.8928387到00:00:06.3839097

3.)使用了WiktorStribiżew正则表达式
从00:00:06.3839097 到00:00:03.2150095

非常感谢你的帮助!!!

3 个答案:

答案 0 :(得分:9)

让我将我的评论“转换”成答案,因为现在我看到你可以对正则表达式的表现做些什么。

As I have mentioned above,将所有.*?替换为[^|]*,并将所有[|][|][|]替换为[|]{3}(或类似,取决于{{1}的数量另外,不要使用嵌套的捕获组,这也会影响性能!

[|]

只有最后一个var logFileFormat = @"(?<time>[^|]*)[|](?<placeholder4>[^|]*)[|](?<source>[^|]*)[|](?<level>[1-3])[|](?<message>[^|]*)[|]{3}(?<placeholder1>[^|]*)[|]{2}(?<placeholder2>[^|]*)[|](?<placeholder3>.*)"; 可以保持“通配符号”,因为它会占据该行的其余部分。

以下是RegexHero上您和我的正则表达式模式的比较。

enter image description here

然后,使用.*

RegexOptions.Compiled

答案 1 :(得分:3)

如果您多次使用相同的正则表达式,请确保编译它,以便每次都不重新创建正则表达式。这可以产生多个数量级。

var regex = new Regex(".*", RegexOptions.Compiled);

以下LinqPad代码显示了3种使用Regex的方法,从最快到最慢。

regexFast方法大约需要5秒钟,regexSlow方法需要6秒钟,regexSlowest大约需要50秒。

void Main()
{
    var sw = new Stopwatch();

    var regex = @"(?<first>T[he]{2})\s*\w{5}.*";

    // This is the fastest method.
    sw.Restart();
    var regexFast = new Regex(regex, RegexOptions.Compiled);
    for (int i = 0; i < 9999999; i++)
    {
        regexFast.Match("The quick brown fox");
    }
    sw.Stop();
    sw.ElapsedMilliseconds.Dump();

    // This is a little slower - we didn't compile the regex so it has 
    // to do some extra work on each iteration.
    sw.Restart();
    var regexSlow = new Regex(regex);
    for (int i = 0; i < 9999999; i++)
    {
        regexSlow.Match("The quick brown fox");
    }
    sw.Stop();
    sw.ElapsedMilliseconds.Dump();

    // This method is super slow - we create a new Regex each time, so 
    // we have to do *lots* of extra work.
    sw.Restart();
    for (int i = 0; i < 9999999; i++)
    {
        var regexSlowest = new Regex(regex);
        regexSlowest.Match("The quick brown fox");
    }
    sw.Stop();
    sw.ElapsedMilliseconds.Dump();
}

答案 2 :(得分:2)

您的正则表达式可以优化为:

(?<time>([^|]*))[|](?<placeholder4>([^|]*))[|](?<source>([^|]*))[|](?<level>[1-3])[|](?<message>([^|]*))[|]{3}(?<placeholder1>([^|]*))[|][|](?<placeholder2>([^|]*))[|](?<placeholder3>([^|]*))

使用negated char类而不是惰性量词。它减少了回溯。通过此更改,Regex101从 316 步骤转到 47 。将它与RB结合起来。你应该没问题