c#regex高CPU使用率

时间:2013-11-13 19:56:21

标签: c# regex

我的小程序正在检查脚本网站使用的类型,它使用超过80%的cpu i7处理器。我不知道这是正常的吗?

代码:

public static class EnginesMatcher
{

    public static readonly Regex Drupal1 =
        new Regex(
            @"/misc/drupal\.js|Drupal\.settings|href=""http://drupal\.org""|\?q=node/[0-9]+|/\?q=user/register|/\?q=user/password|/user/register\?destination|<li class=""collapsed""><a href=""/node/add"">|/dpl3/files/|/modules/node/",
            RegexOptions.Compiled);

    public static readonly Regex XE1 =
        new Regex(
        @"XpressEngine|content=""zeroboardXE|content=""xe_board""|var zbxe_session_name|/xe\.css\?2|/xeicon/favicon\.ico""|#xe-editor-container-1|xpress_xeditor",
            RegexOptions.Compiled);

    //and 60 more such regex

在另一个班级

  public async Task<Result> Match(string url)
        {

            if (!await Open(url).ConfigureAwait(false)) return ResultKey;


            if (EnginesMatcher.Drupal1.IsMatch(html))
            {
                return new Result()
                {
                    Key = AResultKey.Success,
                    LogFile = "Drupal.txt",
                    Message = "Drupal",
                    Url = url
                };
            }
            if (EnginesMatcher.XE1.IsMatch(html))
            {
                return new Result()
                {
                    Key = AResultKey.Success,
                    LogFile = "Drupal.txt",
                    Message = "Drupal",
                    Url = url
                };
            }

Match(url)函数在ForeachAsyncLoop中,程序检查大约4000个链接/分钟。当我禁用所有正则表达式时,它使用高达20%的cpu,我可以提高正则表达式的性能吗?强调文本

2 个答案:

答案 0 :(得分:5)

你可能无法使用正则表达式加快速度。但是,使用不同的算法可能会做得更好。

Aho-Corasick string matching algorithm旨在完成你正在做的事情:在大量文本中寻找一组固定的字符串。

标准算法不支持正则表达式,但您的正则表达式是逐字字符串。也就是说,您正在寻找this|that|something else|something more。这与查找四个不同的字符串相同。

几年前我发布了Aho-Corasick algorithm in C#的实现。通过对您的工作方式进行一些修改,它应该可以正常工作。

首先构建您要查找的字符串字典以及相应的网站:

Dictionary<string, string> StringsToSites = new Dictionary<string, string>();

然后,添加字符串。例如,对于Drupal,您需要添加:

StringsToSites.Add("/misc/drupal\.js", "Drupal");
StringsToSites.Add("Drupal.settings", "Drupal");
StringsToSites.Add(@"href=""http://drupal\.org"", "Drupal");
// problem with this one ...   |\?q=node/[0-9]+
StringsToSites.Add("?q=user/register", "Drupal");
// etc., etc.

请注意,对于非逐字字符串的内容存在问题。实现没有办法匹配“?q = node / [0-9] + /”。我们能做的最好的事情是添加字符串“?q = node /".

然后,创建一个匹配器并填充它:

AhoCorasickStringSearcher matcher = new AhoCorasickStringSearcher();
foreach (var key in StringsToSites.Keys)
{
    matcher.AddItem(key);
}
matcher.CreateFailureFunction();

然后,对于您看到的每个链接,请致电matcher.Search

var Matches = matcher.Search(link);    

这将为您提供StringMatch个对象的集合。您可以在字典中查找Text以查看它匹配的网站。例如:

foreach (var m in Matches)
{
    string site;
    if (StringsToSites.TryGetValue(m.Text, out site))
    {
        Console.WriteLine("Text '{0}' matches site '{1}'.", m.Text, site);
    }
}

我希望这至少是你的正则表达式解决方案的10倍,可能快100倍。

答案 1 :(得分:1)

你正在做的事情是:

  1. 引擎将尝试从字符串的开头按顺序匹配交替。
  2. 按顺序打电话给你的正则表达式。
  3. 试图完成1&amp; 2,你可以将所有正则表达式组合成一个正则表达式。 我不认为这会在组合它们时产生性能损失。甚至可能更有效。

    值得探索,因为无论如何这可能是你代码中的一个慢点。

    所以,相当于你正在做的是:

      Regex rxAll = new Regex(
          @"
               (?:
                    ^ [\S\s]*
                    (?<Drupal1>
                         /misc/drupal\.js
                      |  Drupal\.settings
                      |  href=""http://drupal\.org""
                      |  \?q=node/ [0-9]+
                      |  /\?q=user/register
                      |  /\?q=user/password
                      |  /user/register\?destination
                      |  <li\ class=""collapsed""><a\ href=""/node/add"">
                      |  /dpl3/files/
                      |  /modules/node/
                    )
                 |
                    ^ [\S\s]*
                    (?<XE1>
                         XpressEngine
                      |  content=""zeroboardXE
                      |  content=""xe_board""
                      |  var\ zbxe_session_name
                      |  /xe\.css\?2
                      |  /xeicon/favicon\.ico""
                      |  \#xe-editor-container-1
                      |  xpress_xeditor
                    )
               )
          ", RegexOptions.IgnorePatternWhitespace);
    
      string html =
          @"
             <a class=""x-fn"" href=""javascript:void(0);"">
             <a class='x-fn' href = ""javascript:void(0); "">
             <a href='javascript:void(0);' class=x-fn >
             <a class=""x-fn"" href=javascript:void(0); >
             <a 'hello' href=javascript:void(0); world class=x-fn content=""xe_board"">
          ";
    
      Match matches = rxAll.Match( html );
      if (matches.Success)
      {
          if (matches.Groups["Drupal1"].Success)
          {
              Console.WriteLine("Matched Drupal1 -> {0}", matches.Groups["Drupal1"].Value);
              return;
          }
          if (matches.Groups["XE1"].Success)
          {
              Console.WriteLine("Matched XE1 -> {0}", matches.Groups["XE1"].Value);
              return;
          }
      }
      return;
    

    编辑:BTW,我在你的正则表达式上使用了RegexFormat(.com)程序。这些Verbatim正则表达式是 只需按几下按钮即可完成。因此,您可以使用工具为您完成所有工作。