1

.*テキストで次のような正規表現を照合すると、前後の ( ) 部分がない場合よりもはるかに遅くなることに気付きました。私はperlで同じことをしましたが、perlではほとんど違いがないことがわかりました. "(.*)someRegex(.*)"Javaの元の正規表現を最適化する方法はありますか?

Pattern p = Pattern.compile("(.*)someRegex(.*)");
Matcher m = p.matcher("some text");
m.matches();

Pattern p = Pattern.compile("someRegex");
Matcher m = p.matcher("some text");
m.matches();

編集:具体例を次に示します。

(.*?)<b>\s*([^<]*)\s*<\/b>(.*)
4

3 に答える 3

4

最善の策は、文字列の先頭と末尾を完全に一致させようとすることをスキップすることです。メソッドを使用する場合はそれを行う必要がありますが、matches()メソッドを使用する場合はそうではありませんfind()。それはおそらくあなたが代わりに望むものです。

Pattern p = Pattern.compile("<b>\\s*([^<]*)\\s*<\\/b>");
Matcher m = p.matcher("some <b>text</b>");
m.find();

とを使用start()end()て、一致を含むソース文字列内のインデックスを見つけることができます。一致内のキャプチャの内容(つまり、太字のタグ内のテキスト)group()を見つけるために使用できます。()

私の経験では、正規表現を使用してHTMLを処理することは非常に脆弱であり、最も些細な場合にのみうまく機能します。代わりに本格的なXMLパーサーを使用する方が幸運かもしれませんが、これがこれらの些細なケースの1つである場合は、それを使用してください。

元の回答:これが私の元の回答.*で、試合開始時のパフォーマンスが非常に悪い理由を共有しています。

フロントで使用する場合の問題.*は、試合で多くのバックトラックが発生することです。たとえば、次のことを考慮してください。

Pattern p = Pattern.compile("(.*)ab(.*)");
Matcher m = p.matcher("aaabaaa");
m.matches();

試合は次のように進行します。

  1. マッチャーは、文字列全体「aaabaaa」を最初の文字列に吸い込もうとします.*が、その後、照合を試みてa失敗します。
  2. マッチャーはバックアップして「aaabaa」と一致し、次に一致aを試みて成功しますが、一致bを試みて失敗します。
  3. マッチャーはバックアップして「aaaba」と一致し、次に一致aを試みて成功しますが、一致bを試みて失敗します。
  4. マッチャーはバックアップして「aaab」と一致し、次に一致aして成功しようbとしますが、一致しようとして失敗します。
  5. マッチャーはバックアップして「aaa」と一致し、次に一致しようとしてa失敗します。
  6. マッチャーはバックアップして「aa」を照合し、次に照合aして成功し、試行bして成功し、「aaa」を最後に照合し.*ます。成功。

可能な限り、パターン一致の開始に向けて本当に広い一致を避けたいと考えています。あなたの実際の問題を知らなければ、より良い何かを提案することは非常に難しいでしょう。

更新: Anirudhaは(.*?)ab(.*)、バックトラックを回避するための可能な修正として使用することを提案しています。これにより、バックトラックがある程度短絡しますが、試行ごとに次の一致を適用しようとするという犠牲が伴います。では、次のことを考慮してください。

Pattern p = Pattern.compile("(.*?)ab(.*)");
Matcher m = p.matcher("aaabaaa");
m.matches();

これは次のように進行します。

  1. マッチャーは、最初の「」に何も一致させようとせず、一致させよ.*?うとしてa成功しますが、一致しませんb
  2. マッチャーは、最初の文字「a」を最初の文字に一致させようとし、.*?一致させようとしてa成功しますが、一致しませんb
  3. マッチャーは、最初の2文字「aa」を最初の文字に一致さ.*?せようとし、一致aさせて成功させ、一致さbせて成功させ、残りを.*「aaa」に丸呑みします。成功。

今回はバックトラックはありませんが、内の前進ごとに、より複雑なマッチングプロセスがあります.*?。これは、特定の試合のパフォーマンスの向上、または試合の進行の反復がたまたま遅い場合の損失である可能性があります。

これにより、試合の進行方法も変わります。試合は貪欲で、より保守的.*な場所で可能な限り試合を試みます。.*?

たとえば、文字列「aaabaaabaaa」。

最初のパターンは、(.*)ab(.*)「aaabaa」を最初のキャプチャに一致させ、「aaa」を2番目のキャプチャに一致させます。

2番目のパターンは、(.*?)ab(.*)「aa」を最初のキャプチャに一致させ、「aaabaaa」を2番目のキャプチャに一致させます。

于 2012-09-10T17:08:40.953 に答える
3

代わりに、"(.*)someRegex(.*)"「someRegex」で文字列を分割し、結果の配列からパーツを取得してみませんか? これにより、同じ結果が得られますが、はるかに高速で簡単になります。Java は、必要に応じて正規表現による分割をサポートしています - http://www.regular-expressions.info/java.html

于 2012-09-10T17:12:35.500 に答える
1

.すべての文字に一致

や など.のクラスを使用して検索を制限する代わりに、.\w\s

しかし、私はそれが速く動くことを保証しません.

それはすべて、一致するテキストの量に依存します!

于 2012-09-10T16:47:58.677 に答える