更快地替换正则表达式

时间:2012-01-20 12:22:18

标签: c# regex performance

我在课堂上有大约100个Regex个电话,每个电话都涵盖了文本协议中不同类型的数据,但我有很多文件并基于分析regex占用了我的代码的88%。

很多这类代码:

{
  Match m_said = Regex.Match(line, @"(.*) said,", RegexOptions.IgnoreCase);
  if (m_said.Success)
  {
    string playername = ma.Groups[1].Value;
    // some action
    return true;
  }
}

{
  Match ma = Regex.Match(line, @"(.*) is connected", RegexOptions.IgnoreCase);
  if (ma.Success)
  {
    string playername = ma.Groups[1].Value;
    // some action
    return true;
  }
}
{
  Match ma = Regex.Match(line, @"(.*): brings in for (.*)", RegexOptions.IgnoreCase);
  if (ma.Success)
  {
    string playername = ma.Groups[1].Value;
    long amount = Detect_Value(ma.Groups[2].Value, line);
    // some action
    return true;
  }
}

有没有办法用其他更快的解决方案替换Regex

5 个答案:

答案 0 :(得分:8)

对于在循环中测试的正则表达式,在循环之外预编译它们通常更快,并且只在循环内测试它们。

您需要先使用各自的模式声明不同的正则表达式,然后只调用带有文本的Match()以进行第二步测试。

答案 1 :(得分:3)

除了预编译正则表达式之外,通过编写更精确的正则表达式,您可以获得(可能更多)性能优势。在这方面,.*几乎总是一个糟糕的选择:

(.*) is connected表示:首先匹配整个字符串(即.*部分),然后一次回溯一个字符,直到可以匹配is connected

现在,除非字符串非常短或is connected非常接近字符串的末尾,否则会导致大量的回溯,这会耗费时间。

因此,如果您可以优化允许的匹配,则可以提高性能。

例如,如果只允许使用字母数字字符,那么(\w+) is connected就会很好。如果它是任何类型的非空白字符,则使用(\S+) is connected。等等,取决于有效匹配的规则。

在您的具体示例中,您似乎没有对捕获的匹配执行任何操作,因此您甚至可以完全删除正则表达式并只查找固定的子字符串。哪种方法最快将取决于您的实际输入和要求。

答案 2 :(得分:2)

我不知道你是否可以重用表达式,或者多次调用该方法,但如果是这样,你应该预编译你的正则表达式。试试这个:

private static readonly Regex xmlRegex = new Regex("YOUR EXPRESSION", RegexOptions.Compiled);

在您的示例中,每次使用该方法时,它都会“编译”表达式,但这是不必要的,因为表达式是const。现在预编译只编译一次。缺点是第一次访问表达式时,它会慢一些。

答案 3 :(得分:1)

您可以尝试预先编译正则表达式或考虑将所有单独的正则表达式组合成一个(怪物)正则表达式:

Match m_said = Regex.Match(line,
            @"(.*) (said|(is connected)|...|...),",
            RegexOptions.IgnoreCase);

然后,您可以测试第二个捕获组以确定发生了哪种类型的匹配。

答案 4 :(得分:1)

我知道Regex可以做很多事情,但这里是Regex与char.Split对比string.split的基准

http://www.dotnetperls.com/split 在基准部分