[英]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.