Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#正则表达式性能非常慢_C#_Regex - Fatal编程技术网

C#正则表达式性能非常慢

C#正则表达式性能非常慢,c#,regex,C#,Regex,我对正则表达式的话题很陌生。我想用以下正则表达式解析日志文件: (?<time>(.*?))[|](?<placeholder4>(.*?))[|](?<source>(.*?))[|](?<level>[1-3])[|](?<message>(.*?))[|][|][|](?<placeholder1>(.*?))[|][|](?<placeholder2>(.*?))[|](?<placeholder3

我对正则表达式的话题很陌生。我想用以下正则表达式解析日志文件:

(?<time>(.*?))[|](?<placeholder4>(.*?))[|](?<source>(.*?))[|](?<level>[1-3])[|](?<message>(.*?))[|][|][|](?<placeholder1>(.*?))[|][|](?<placeholder2>(.*?))[|](?<placeholder3>(.*))
带有appr的日志文件。3000行需要很长的时间来解析它。你有没有一些加快表演的提示?谢谢你

更新: 我使用regex是因为我使用不同的日志文件,这些文件的结构不同,我使用它的方式是:

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。已编译:
从00:01:10.9611143到00:00:38.8928387

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

3.)使用过的Wiktor Stribiżew regex

从00:00:06.3839097到00:00:03.2150095

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

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();
}
void Main()
{
var sw=新秒表();
var regex=@“(?T[he]{2})\s*\w{5}.*”;
//这是最快的方法。
sw.Restart();
var regexFast=newregex(Regex,RegexOptions.Compiled);
对于(int i=0;i<999999;i++)
{
regexFast.Match(“快速棕色狐狸”);
}
sw.Stop();
sw.elapsedmillesons.Dump();
//这有点慢-我们没有编译正则表达式,所以它有
//在每次迭代中做一些额外的工作。
sw.Restart();
var regexSlow=新正则表达式(Regex);
对于(int i=0;i<999999;i++)
{
regexSlow.Match(“快速棕色狐狸”);
}
sw.Stop();
sw.elapsedmillesons.Dump();
//这个方法非常慢-我们每次都创建一个新的正则表达式,所以
//我们必须做很多额外的工作。
sw.Restart();
对于(int i=0;i<999999;i++)
{
var regexSlowest=新正则表达式(Regex);
regexSlowest.Match(“快速棕色狐狸”);
}
sw.Stop();
sw.elapsedmillesons.Dump();
}

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

(?<time>([^|]*))[|](?<placeholder4>([^|]*))[|](?<source>([^|]*))[|](?<level>[1-3])[|](?<message>([^|]*))[|]{3}(?<placeholder1>([^|]*))[|][|](?<placeholder2>([^|]*))[|](?<placeholder3>([^|]*))
(?([|]*)[|][|](?([|]*)[|](?([|]*))[|](?[1-3])[|](?([|]*)[|]{3}(?([|]*)[|][|][|](?([|]*)[|])[|][|]]((?([|]*))[|])[|]
使用否定的char类而不是惰性量词。它减少了回溯。通过此更改,Regex101从316个步骤变为47个步骤。将它与RB的答案结合起来,您应该会很好

让我将我的评论“转换”为答案,因为现在我知道您可以对regex性能做些什么了

,将所有
*?
替换为
[^ |]*
,并将所有重复的
[|][|][|][|][|]
替换为
[|]{3}
(或类似内容,具体取决于
[|]
的数量。此外,不要使用嵌套的捕获组,这也会影响性能

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

为什么要使用正则表达式呢?似乎您可以使用
String.Split
来获取列数组。除非您确实需要选择这种类型的行(在特定列中包含数字),否则您确实可以使用
String.Split()
。否则,将所有
*?
替换为
[^ |]*
,用
[|][|][|][|][|]
替换
[|]{3}也可以提高速度
。实际上,即使您需要检查某个特定列值是否为数字,您也可以使用非正则表达式代码进行检查……您还没有向我们展示如何实际匹配正则表达式-请添加相关代码。哦,是的,正则表达式对象(如果使用非静态方法)应该在循环之外创建。字符类
[|]
似乎是一种获取一个字符的低效方法。正则表达式引擎可能会将其优化为单个显式字符,但可能不会。我会在整个过程中将它们替换为
\\
。您也可以使用正则表达式缓存:perf应该类似于第二种方式编译的
可能会有所帮助,正如RB所说,但是那些
*?
>s才是真正的问题。我会在处理时去掉嵌套组。您也可以使用RegexOptions.ExplicitCapture来删除嵌套的捕获组。这很有意义,因为命名组将捕获相关的详细信息。
Regex pattern = new Regex(LogFormat.GetLineRegex(logFileFormat), RegexOptions.Compiled);