2009-06-18 7 views
12

replaceメソッドが指定された文字列の内容を置き換えるのではなく、文字列オブジェクトを返すという事実は少し鈍いですが、文字列がJavaでは不変であることがわかっているときはわかります。私はいくつかのコードで深くネストされた置き換えを使用して、大きなパフォーマンスのヒットを取っています。私はそれをより速くするために置き換えることができるものはありますか?Java文字列のメソッドを置き換えるより高速な代替方法はありますか?

+5

heh heh replace replace – ojblass

+1

文字列を使用していますか?ばかじゃないの?バイトの配列を使用してください! – IAdapter

答えて

19

これはStringBuilderの意味です。多くの操作を行う場合は、StringBuilderで行い、必要なときはいつでもStringに変換してください。

StringBuilderをこのように説明されています

を「可変の文字列をこのクラスは、StringBufferをと互換性のあるAPIを提供しますが、同期の保証なし」。

それはreplace(とappendinsertdeleteら)を持って、あなたは本当のStringにそれをモーフィングするtoStringを使用することができます。

+0

また、スレッドセーフティを必要としない場合は、StringBuilderを使用することを忘れないでください。 –

+0

また、StringBuilder.replaceはString.replaceとは全く異なる働きをしますので、ドロップインの代わりに使用することはできません! –

0

一般に、すべての文字列操作は非常に遅いです。 StringBufferの使用を検討してください。Stringクラスとまったく同じではありませんが、共通点が多く、変更可能です。

+1

一般に、バッファをスレッドセーフにする必要がない(つまり、同じバッファを同時に操作する複数のスレッドを持たない)場合は、StringBufferの代わりにStringBuilderを使用する必要があります。 – Avi

+2

StringBufferドキュメントから:StringBuilderクラスは、同じ操作のすべてをサポートしていますが、同期を実行しないため、より速いので、一般的にこれに優先して使用する必要があります。 – tgamblin

+0

私は、マルチスレッド環境で多くの作業をしていたので、StringBufferが自然に思い浮かぶようになりました。 –

7

前の投稿は正しいですが、StringBuilder/StringBufferは解決策です。

しかし、メモリー内の大きな文字列で置き換えを行うことをお勧めしますか?

私はしばしばストリームとして実装されている文字列操作をしているので、文字列で置き換えてOutputStreamに送るのではなく、Stringを出力ストリームに送る瞬間に置き換えます。それはどの交換よりもはるかに高速です。

この置換によってテンプレートメカニズムを実装する場合は、これははるかに高速です。ストリーミングは、メモリ消費量が少ないので常に高速で、クライアントの速度が遅い場合は、遅いペースで生成する必要があります。

+2

例を挙げることはできますか? –

1

置き換えられる文字列(XMLエスケープシーケンスなど)がある場合、特に置き換えのパターンがパターンと異なる場合は、処理の提案と同様に、FSMレクサータイプのアルゴリズムが最も効率的であるようですストリーム形式で出力が段階的に構築されます。

おそらくMatcherオブジェクトを使用して効率的に行うことができます。

1

Stringchar[]を取得し、それを繰り返してください。一時的なStringBuilderを使用してください。

パターンが見つからない場合は、繰り返してパターンを検索し、スキャンしたものをStringBuilderに書き込み、それ以外の場合はStringBuilderに置き換えます。

2

@paxdiabloの回答に加えて、StringBuffersを使用するreplaceAllの実装例です。StringBuffersは文字列より約3.7倍高速です。でReplaceAll():

コード:

public static String replaceAll(final String str, final String searchChars, String replaceChars) 
{ 
    if ("".equals(str) || "".equals(searchChars) || searchChars.equals(replaceChars)) 
    { 
    return str; 
    } 
    if (replaceChars == null) 
    { 
    replaceChars = ""; 
    } 
    final int strLength = str.length(); 
    final int searchCharsLength = searchChars.length(); 
    StringBuilder buf = new StringBuilder(str); 
    boolean modified = false; 
    for (int i = 0; i < strLength; i++) 
    { 
    int start = buf.indexOf(searchChars, i); 

    if (start == -1) 
    { 
     if (i == 0) 
     { 
     return str; 
     } 
     return buf.toString(); 
    } 
    buf = buf.replace(start, start + searchCharsLength, replaceChars); 
    modified = true; 

    } 
    if (!modified) 
    { 
    return str; 
    } 
    else 
    { 
    return buf.toString(); 
    } 
} 

テストケース - 出力は、以下の(デルタ1 = 1917009502; DELTA2 = 7241000026)です:

@Test 
public void testReplaceAll() 
{ 
    String origStr = "1234567890-1234567890-"; 

    String replacement1 = StringReplacer.replaceAll(origStr, "0", "a"); 
    String expectedRep1 = "123456789a-123456789a-"; 

    String replacement2 = StringReplacer.replaceAll(origStr, "0", "ab"); 
    String expectedRep2 = "123456789ab-123456789ab-"; 

    String replacement3 = StringReplacer.replaceAll(origStr, "0", ""); 
    String expectedRep3 = "123456789-123456789-"; 


    String replacement4 = StringReplacer.replaceAll(origStr, "012", "a"); 
    String expectedRep4 = "1234567890-1234567890-"; 

    String replacement5 = StringReplacer.replaceAll(origStr, "123", "ab"); 
    String expectedRep5 = "ab4567890-ab4567890-"; 

    String replacement6 = StringReplacer.replaceAll(origStr, "123", "abc"); 
    String expectedRep6 = "abc4567890-abc4567890-"; 

    String replacement7 = StringReplacer.replaceAll(origStr, "123", "abcdd"); 
    String expectedRep7 = "abcdd4567890-abcdd4567890-"; 

    String replacement8 = StringReplacer.replaceAll(origStr, "123", ""); 
    String expectedRep8 = "4567890-4567890-"; 

    String replacement9 = StringReplacer.replaceAll(origStr, "123", ""); 
    String expectedRep9 = "4567890-4567890-"; 

    assertEquals(replacement1, expectedRep1); 
    assertEquals(replacement2, expectedRep2); 
    assertEquals(replacement3, expectedRep3); 
    assertEquals(replacement4, expectedRep4); 
    assertEquals(replacement5, expectedRep5); 
    assertEquals(replacement6, expectedRep6); 
    assertEquals(replacement7, expectedRep7); 
    assertEquals(replacement8, expectedRep8); 
    assertEquals(replacement9, expectedRep9); 

    long start1 = System.nanoTime(); 
    for (long i = 0; i < 10000000L; i++) 
    { 
    String rep = StringReplacer.replaceAll(origStr, "123", "abcdd"); 
    } 
    long delta1 = System.nanoTime() -start1; 

    long start2= System.nanoTime(); 

    for (long i = 0; i < 10000000L; i++) 
    { 
    String rep = origStr.replaceAll("123", "abcdd"); 
    } 

    long delta2 = System.nanoTime() -start1; 

    assertTrue(delta1 < delta2); 

    System.out.printf("Delta1 = %d; Delta2 =%d", delta1, delta2); 


} 
0

あなたは、単一の文字を置き換えていますあなたのキャラクタ配列を反復することを考えてください。ただし、(事前に作成された)HashMap<Character, Character>()を使って文字を置き換えてください。

私はこの方針を使用して、整数指数文字列をユニコードの上付き文字で変換します。

String.replace(char, char)と比べて約2倍の速さです。この比較では、ハッシュマップの作成に関連する時間は含まれていないことに注意してください。

3

以下のコードは約です。一致がない場合は30倍、一致する場合は5倍速くなります。

static String fastReplace(String str, String target, String replacement) { 
    int targetLength = target.length(); 
    if(targetLength == 0) { 
     return str; 
    } 
    int idx2 = str.indexOf(target); 
    if(idx2 < 0) { 
     return str; 
    } 
    StringBuilder buffer = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); 
    int idx1 = 0; 
    do { 
     buffer.append(str, idx1, idx2); 
     buffer.append(replacement); 
     idx1 = idx2 + targetLength; 
     idx2 = str.indexOf(target, idx1); 
    } while(idx2 > 0); 
    buffer.append(str, idx1, str.length()); 
    return buffer.toString(); 
} 
関連する問題