簡體   English   中英

C# 正則表達式性能很慢

[英]C# Regex Performance very slow

我對正則表達式主題很陌生。 我想用以下正則表達式解析日志文件:

(?<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.) 使用 Wiktor Stribiżew 正則表達式
從 00:00:06.3839097到 00:00:03.2150095

讓我將我的評論“轉換”為答案,因為現在我知道您可以對正則表達式的性能做些什么。

正如我上面提到的,替換所有.*? [^|]* ,以及所有重復[|][|][|][|]{3} (或類似的,取決於[|]的數量。另外,不要使用嵌套的捕獲組,即也影響性能!

var logFileFormat = @"(?<time>[^|]*)[|](?<placeholder4>[^|]*)[|](?<source>[^|]*)[|](?<level>[1-3])[|](?<message>[^|]*)[|]{3}(?<placeholder1>[^|]*)[|]{2}(?<placeholder2>[^|]*)[|](?<placeholder3>.*)";

只有最后一個.*可以保持“通配符”,因為它將占據該行的其余部分。

這是您和我在RegexHero 上的正則表達式模式的比較

在此處輸入圖片說明

然后,使用RegexOptions.Compiled

Regex pattern = new Regex(LogFormat.GetLineRegex(logFileFormat), RegexOptions.Compiled);

如果您多次使用相同的正則表達式,請確保對其進行編譯,以免每次都重新創建正則表達式。 這可以產生多個數量級。

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

以下 LinqPad 代碼顯示了使用正則表達式的 3 種方法,從最快到最慢。

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();
}

您的正則表達式可以優化為:

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

使用否定字符類而不是惰性量詞。 它減少了回溯。 Regex101 從316步變成了47步。 將它與 RB. 的答案結合起來,你應該沒問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM