2009-06-18 88 views
12

替換方法返回一個字符串對象而不是替換給定字符串的內容的事實有點過時(但知道字符串在Java中是不可變的時候可以理解)。我在某些代碼中使用深度嵌套替換來獲得主要性能。有什麼我可以用它代替它會更快?在Java字符串中替換方法的更快選擇?

+5

heh heh replace replace – ojblass 2009-06-18 05:40:31

+1

您使用字符串嗎?你瘋了嗎?使用字節數組! – IAdapter 2009-06-18 07:18:49

回答

19

這就是StringBuilder的意思。如果您要進行大量操作,請在StringBuilder上執行此操作,然後在需要時將其轉換爲String

StringBuilder被如此描述:

「一個可變的字符序列該類提供與兼容的StringBuffer的API,但不保證同步的」。

replace(和appendinsertdelete,等),你可以使用toString把它演變成一個真正的String

+0

還記得使用StringBuilder,如果你不需要線程安全,它通常更快,工作原理相同。 – 2009-07-10 21:34:24

+0

此外,StringBuilder.replace的工作方式與String.replace完全不同,因此您不能將其用作插入替換! – 2017-08-28 12:23:28

0

所有字符串操作通常都很慢。考慮使用StringBuffer,它不完全像String類,但有很多共同點,它也是可變的。

+1

一般來說,如果你不需要你的緩衝區是線程安全的(即你沒有多個線程一次操作同一個緩衝區),你應該使用StringBuilder而不是StringBuffer。 – Avi 2009-06-18 05:46:03

+2

從StringBuffer文檔中:StringBuilder類通常應該優先於此類使用,因爲它支持所有相同的操作,但速度更快,因爲它不執行同步。 – tgamblin 2009-06-18 05:48:10

+0

我曾經在多線程環境下工作過很多,所以StringBuffer自然而然地進入了我的腦海。 – 2009-06-18 05:50:38

7

以前的帖子是對的,StringBuilder/StringBuffer是一個解決方案。

但是,你也必須質疑,如果在內存中的大字符串上進行替換是一個好主意。

我經常有作爲流實現的字符串操作,所以不是將其替換爲字符串,然後將其發送到OutputStream,而是在將字符串發送到輸出流時進行替換。這比任何替換都快得多。

如果你想讓這個替換實現一個模板機制,這會更快。由於您消耗的內存較少,並且如果客戶端速度較慢,您只需要以較慢的速度生成流式處理,因此流式處理速度總是更快 - 因此它可以更好地擴展。

+2

你能提供一個例子嗎? – 2012-07-24 19:00:41

1

如果您有多個要替換的字符串(例如XML轉義序列),尤其是在替換與模式長度不同的情況下,FSM詞法分析器類型算法似乎可能最有效,類似於處理建議以流的方式,輸出增量式構建。

也許一個匹配對象可以用來做到這一點。

1

只需獲取Stringchar[]並遍歷它。使用臨時的StringBuilder

查找要在迭代如果你沒有找到模式,寫你掃描到StringBuilder的東西,否則寫替換文本到StringBuilder更換模式。

2

添加到@paxdiablo答案,這裏是一個使用StringBuffers的替換所有實例,比String快約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(); 
    } 
} 

測試用例 - 輸出以下(DELTA1 = 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>()替換字符。

我使用這種策略來通過unicode上標字符轉換整數指數字符串。

這個速度比String.replace(char, char)快兩倍。請注意,創建哈希映射關聯的時間不包含在此比較中。

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(); 
}