6

我正在编写一个 C# 应用程序,它在很多(约 2500 万)字符串上运行多个正则表达式(约 10)。我确实尝试用谷歌搜索这个,但是任何搜索“减慢”的正则表达式都充满了关于反向引用等如何减慢正则表达式的教程。我假设这不是我的问题,因为我的正则表达式开始快而慢。

对于前一百万个左右的字符串,每 1000 个字符串大约需要 60 毫秒来运行正则表达式。到最后,它的速度减慢到大约需要 600 毫秒。有谁知道为什么?

情况更糟,但我通过使用实例RegEx而不是缓存版本并尽可能编译表达式来改进它。

我的一些正则表达式需要有所不同,例如取决于用户名,它可能是 mike said (\w*)john said (\w*)

我的理解是不可能编译这些正则表达式并传入参数(例如saidRegex.Match(inputString, userName))。

有没有人有什么建议?

[编辑以准确反映速度 - 每 1000 个字符串,而不是每字符串]

4

2 回答 2

2

这可能不是您关于 RegEx 性能下降的问题的直接答案——这有点令人着迷。但是 - 在阅读了上面的所有评论和讨论之后 - 我建议以下内容:

解析一次数据,将匹配的数据拆分到数据库表中。看起来您正在尝试捕获以下字段:

Player_Name | Monetary_Value

如果您要创建每行包含这些值的数据库表,然后在创建时捕获每个新行 - 解析它 - 并附加到数据表 - 您可以轻松地对数据进行任何类型的分析/计算- 无需一次又一次地解析 25M 行(这是一种浪费)。

此外 - 在第一次运行时,如果您要将 25M 记录分解为 100,000 个记录块,然后运行算法 250 次(100,000 x 250 = 25,000,000) - 您可以享受您所描述的所有性能而不会减速,因为你把工作分块了。

换句话说 - 考虑以下几点:

  1. 创建数据库表如下:

    CREATE TABLE PlayerActions (
        RowID          INT PRIMARY KEY IDENTITY,
        Player_Name    VARCHAR(50) NOT NULL,
        Monetary_Value MONEY       NOT NULL
    )
    
  2. 创建一个算法,将 25m 行分解为 100k 块。使用 LINQ / EF5 作为假设的示例。

    public void ParseFullDataSet(IEnumerable<String> dataSource) {
        var rowCount = dataSource.Count();
        var setCount = Math.Floor(rowCount / 100000) + 1;
    
        if (rowCount % 100000 != 0)
            setCount++;
    
        for (int i = 0; i < setCount; i++) {
            var set = dataSource.Skip(i * 100000).Take(100000);
            ParseSet(set);
        }
    }
    
    public void ParseSet(IEnumerable<String> dataSource) {
        String playerName = String.Empty;
        decimal monetaryValue = 0.0m;
    
        // Assume here that the method reflects your RegEx generator.
        String regex = RegexFactory.Generate();
    
        for (String data in dataSource) {
            Match match = Regex.Match(data, regex);
            if (match.Success) {
                playerName = match.Groups[1].Value;
    
                // Might want to add error handling here.
                monetaryValue = Convert.ToDecimal(match.Groups[2].Value);
    
                db.PlayerActions.Add(new PlayerAction() {
                    // ID = ..., // Set at DB layer using Auto_Increment
                    Player_Name = playerName,
                    Monetary_Value = monetaryValue
                });
                db.SaveChanges();
    
                // If not using Entity Framework, use another method to insert
                // a row to your database table.
            }
        }
    }
    
  3. 运行上述一次以加载所有预先存在的数据。

  4. 在某处创建一个钩子,允许您检测新行的添加。每次创建新行时,调用:

    ParseSet(new List<String>() { newValue });
    

    或者如果一次创建多个,请调用:

    ParseSet(newValues); // Where newValues is an IEnumerable<String>
    

现在,您可以从数据中进行任何计算分析或数据挖掘,而不必担心超过 2500 万行的动态性能。

于 2013-02-21T23:26:19.653 回答
0

正则表达式确实需要时间来计算。但是,U 可以使用一些技巧使其紧凑。您还可以在 C# 中使用字符串函数来避免正则表达式函数。

代码会很长,但可能会提高性能。String 有几个功能可以剪切和提取字符并根据需要进行模式匹配。例如:IndeOfAny、LastIndexOf、Contains....

string str= "mon";
string[] str2= new string[] {"mon","tue","wed"};

if(str2.IndexOfAny(str) >= 0)
{
  //success code//
}
于 2013-03-15T11:48:09.777 回答