1

Razor テンプレート言語の (非常に小さな) サブセットを解析する正規表現があります。最近、正規表現にさらにいくつかのルールを追加したため、実行が大幅に遅くなりました。私は疑問に思っています:遅いことが知られている特定の正規表現構造はありますか? 読みやすさを維持しながらパフォーマンスを向上させる、使用しているパターンの再構築はありますか? 注: このパフォーマンス ヒットはコンパイル後に発生することを確認しました。

パターンは次のとおりです。

new Regex(
              @"  (?<escape> \@\@ )"
            + @"| (?<comment> \@\* ( ([^\*]\@) | (\*[^\@]) | . )* \*\@ )"
            + @"| (?<using> \@using \s+ (?<namespace> [\w\.]+ ) (\s*;)? )"

            // captures expressions of the form "foreach (var [var] in [expression]) { <text>" 
/* ---> */      + @"| (?<foreach> \@foreach \s* \( \s* var \s+ (?<var> \w+ ) \s+ in \s+ (?<expressionValue> [\w\.]+ ) \s* \) \s* \{ \s* <text> )"

            // captures expressions of the form "if ([expression]) { <text>" 
/* ---> */      + @"| (?<if> \@if \s* \( \s* (?<expressionValue> [\w\.]+ ) \s* \) \s* \{ \s* <text> )"  

            // captures the close of a razor text block
            + @"| (?<endBlock> </text> \s* \} )"

            // an expression of the form @([(int)] a.b.c)
            + @"| (?<parenAtExpression> \@\( \s* (?<castToInt> \(int\)\s* )? (?<expressionValue> [\w\.]+ ) \s* \) )"
            + @"| (?<atExpression> \@ (?<expressionValue> [\w\.]+ ) )"
/* ---> */      + @"| (?<literal> ([^\@<]+|[^\@]) )",
            RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);

/* ---> */ は、速度低下の原因となった新しい「ルール」を示します。

4

2 に答える 2

1

式を固定していないため、一致が見つからないことを確認する前に、エンジンは文字列のすべての位置で各代替サブパターンをチェックする必要があります。これには常に時間がかかりますが、どうすれば時間を短縮できますか?

いくつかの考え:

コメントを一致させようとする 2 行目のサブパターンが気に入らず、正しく動作しないと思います。

( ([^\*]\@) | (\*[^\@]) | . )*-allow@*コメント内で何をしようとしているのかがわかりますが、それぞれの前*または後にはありません@。しかし、グループの*量指定子と 3 番目のオプション.により、サブパターンは問題なく一致*@するため、他のオプションは冗長になります。

一致させようとしているRazorのサブセットが複数行のコメントを許可していないと仮定すると、2行目に提案します

+ @"| (?<comment> @\*.*?\*@ )"

つまり、最初の文字が検出されるまで、任意の文字 (改行を除く) に遅延一致*@します。RegexOptions.ExplicitCapture名前付きグループのみがキャプチャされているという意味を使用しているため、の欠如は()問題になりません。

([^\@<]+|[^\@])また、最後の行のサブパターンも好きではありません([^\@<]+|<)。または[^\@<]+に遭遇しない限り、 は貪欲に文字列の末尾に一致します。@<

同じテキストに一致する隣接するサブパターンは見当たりません。これは、過度のバックトラッキングの通常の\s*原因ですが、何も一致しないことや改行を含む貪欲さと柔軟性のために、すべてが疑わしいようです。おそらく、改行を一致させたくないことがわかっている場所の一部を変更できます\s*。たとえば、 .[ \t]*if

nhahtdh が、アトミック グループ化を使用して、エンジンが以前に一致したものに戻るのを防ぐことを提案していることに気付きました。これは、エンジンが原因となっている一致を見つけることができなくなったときに引き起こされる過度のバックトラックであることはほぼ確実であるため、実験する価値があることは確かです。スローダウン。

オプションで何を達成しようとしていRegexOptions.Multilineますか?使用していないように見えるため^$効果はありません。

のエスケープ@は不要です。

于 2013-03-13T19:39:20.970 に答える