0

必要に応じて正規表現を使用できるかどうかを確認するための簡単なテスト アプリケーションを作成しました。提供されたテキスト ファイル内のすべての重複タグを見つけて、いくつかの一意の文字列に置き換える必要があります。たとえば、あるテキストが入力ファイルで 2 回以上見つかった場合、その出現箇所はすべて {1} に置き換える必要があります。

この目的のために、次のスニペットを作成しました。

    static void Main(string[] args)
    {
        StringBuilder xml = new StringBuilder(File.ReadAllText(@"C:\Integration\Item-26 - Copy.xml"));

        Regex r = new Regex(
            @"(?<exp>\<(?<tag>[^\<\>\s]+)[^\<\>]*\>[^\<\>]+\<\/\k<tag>\>).*\k<exp>", 
            RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

        List<string> values = new List<string>();

        MatchCollection matches = r.Matches(xml.ToString());

        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        while (matches.Count > 0)
        {
            foreach (Match m in matches)
            {
                string matchValue = m.Groups["exp"].Value;
                values.Add(matchValue);
                xml.Replace(matchValue, string.Concat("{" + (values.Count - 1) + "}"));
            }

            Console.WriteLine("Analyzed " + matches.Count + " matches, total replacements = " + values.Count);

            matches = r.Matches(xml.ToString());
        }

        stopwatch.Stop();

        Console.WriteLine("=============== " + stopwatch.Elapsed.TotalSeconds);
        Console.ReadLine();
    }

問題は、入力として大きなファイル (>1MB) がある場合、一致を見つけるための各呼び出しに以前よりも時間がかかることです。最初は、matches.Count を呼び出すのに 0.3 秒かかります。そして、100回の反復の後、1分以上かかります。

テストアプリによるメモリ使用量を確認しましたが、実際に増加することなく、ほとんど何も消費しません。

何が原因で、どうすれば安定したパフォーマンスを得ることができますか? 前もって感謝します。

4

1 に答える 1

1

ここが問題だと思います。あなたの正規表現は次のとおりです。

@"(?<exp>\<(?<tag>[^\<\>\s]+)[^\<\>]*\>[^\<\>]+\<\/\k<tag>\>).*\k<exp>"

だからあなたは次のようなものを探しています:

<tag>stuff</tag>lots of stuff here<tag>stuff</tag>

最初の反復では、タグが互いに近接しているため、内側のタグが置き換えられるため、正規表現はすぐに失敗します。ただし、より多くの内部タグが置換されると、タグ間のスペースが増加します。すぐに次のことができます。

<tag>stuff</tag>hundreds of kilobytes<tag2>other stuff</tag2><tag>stuff</tag>

そして、後戻りはあなたを殺し始めます。

.*を(または.*?以前に提案したもの)を に置き換えることで、これを解決できると思います[^\<]*。を見つけたら<、一致するものを見つけたか、明確な失敗であることがわかっているからです。

于 2013-04-18T05:06:18.490 に答える