web-dev-qa-db-ja.com

文字列replaceAll()とMatcher replaceAll()(パフォーマンスの違い)

非常に簡単な質問ですが、これは、Javaの複雑さに慣れるC/C++の人から来ています。

答えを得るために、jUnitと自分自身のいくつかのパフォーマンステストを実行できることを理解しています。しかし、私はこれがそこにあるかどうか疑問に思っています。

パフォーマンスに関して、String.replaceAll()とMatcher.replaceAll()(Regex.Patternから作成されたMatcherオブジェクト上)の間に既知の違いはありますか?

また、両者の高レベルAPI 'ishの違いは何ですか? (不変性、NULLの処理、空の文字列の処理、コーヒーの製造など)

44
Suvesh Pratapa

String.replaceAll()のソースコード:

public String replaceAll(String regex, String replacement) {
    return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}

最初にパターンをコンパイルする必要があります-短い文字列で同じパターンを使用して何度も実行する場合、コンパイルされたパターンを再利用するとパフォーマンスが大幅に向上します。

23

主な違いは、Patternの生成に使用されるMatcherを保持する場合、使用するたびに正規表現の再コンパイルを回避できることです。 Stringを通過すると、このような「キャッシュ」機能を取得できません。

毎回異なる正規表現がある場合は、StringクラスのreplaceAllを使用するのが適切です。同じ正規表現を多くの文字列に適用する場合は、1つのPatternを作成して再利用します。

9
erickson

不変性/スレッドセーフティ:コンパイルされたパターンは不変ですが、マッチャーは不変です。 ( Is Java Regex Thread Safe? を参照)

空の文字列の処理:replaceAllは空の文字列を適切に処理する必要があります(空の入力文字列パターンとは一致しません)

コーヒーなどを作る:最後に聞いたところ、文字列もパターンもマッチャーもそのためのAPI機能を持っていませんでした。

編集:NULLの処理に関しては、StringとPatternのドキュメントは明示的に言っていませんが、Stringを期待しているため、NullPointerExceptionがスローされると思われます。

6
Jason S

違いは、String.replaceAll()が呼び出されるたびに正規表現をコンパイルすることです。コンパイル済みの正規表現を自動的にキャッシュする.NETの静的Regex.Replace()メソッドに相当するものはありません。通常、replaceAll()は一度しか実行しませんが、特にループ内で同じ正規表現で繰り返し呼び出す場合は、Patternオブジェクトを作成してMatcherメソッドを使用する必要があります。

事前にMatcherを作成し、reset()メソッドを使用して、使用するたびにリターゲットすることもできます。

Matcher m = Pattern.compile(regex).matcher("");
for (String s : targets)
{
  System.out.println(m.reset(s).replaceAll(repl));
}

もちろん、Matcherを再利用することによるパフォーマンス上のメリットは、パターンを再利用することほど優れたものではありません。

4
Alan Moore

String.replaceAllの実装により、知る必要があるすべてのことがわかります。

return Pattern.compile(regex).matcher(this).replaceAll(replacement);

(そして、ドキュメントは同じことを言っています。)

キャッシングをチェックしていませんが、パターンをコンパイルすることを確実に期待していますonce毎回同じパターンでPattern.compileを呼び出すよりも静的な参照を保持する方が効率的です。キャッシュがある場合、それは小さな効率の節約になります-ない場合、それは大きなものになる可能性があります。

4
Jon Skeet

他の回答はOPのパフォーマンス部分を十分にカバーしていますが、Matcher::replaceAllString::replaceAllの別の違いも、独自のPatternをコンパイルする理由です。 Patternを自分でコンパイルするとき、正規表現の適用方法を変更するフラグなどのオプションがあります。例えば:

Pattern myPattern = Pattern.compile(myRegex, Pattern.CASE_INSENSITIVE);

Matcherは、Matcher::replaceAllを呼び出すときに設定したすべてのフラグを適用します。

他にも設定できるフラグがあります。ほとんどの場合、PatternおよびMatcher AP​​Iには多くのオプションがあり、それが単純なString::replaceAllを超える主な理由であることを指摘したかっただけです。

0
Indigenuity