2014-11-05 56 views
8

我需要有一個模式刪除,如果出現很長的字符串。但它出現在字符串中是一個難以置信的邊緣情況。如果找不到匹配項,替換會做什麼? (引擎蓋下)

如果我這樣做:

str = str.replace("pattern", ""); 

那麼它看起來像我創建一個新的字符串(因爲Java字符串是不可變的),這將是一種浪費,如果原來的字符串被罰款。我應該首先檢查一場比賽,然後只在發現比賽時才進行替換?

+0

'如果找不到匹配項,替換操作會怎樣?'Ans;它按原樣打印原始字符串。 – 2014-11-05 06:27:10

+1

@AvinashRaj確實。你讀完了嗎? – ColBeseder 2014-11-05 06:28:37

+1

我發現的一個版本的String.java似乎經過了正則表達式模式匹配器來實現'replace()',即使沒有涉及正則表達式。看起來這可能會讓事情變慢一些,但是你必須對它進行基準測試,並且JVM的答案可能會有所不同。在任何情況下,由於javadoc沒有指定,所以不要**替換爲'=='或'!='的結果。 – ajb 2014-11-05 06:46:41

回答

10

簡短的回答

檢查各種實現方式的文件,沒有一個似乎需要String.replace(CharSequence, CharSequence)方法如果找不到匹配,則返回相同的字符串。

沒有從文檔的要求,執行可能會或可能不會優化沒有發現匹配的情況下的方法。最好編寫代碼,就好像沒有優化一樣,以確保它在任何實現或版本的JRE上正確運行。

特別是,當發現不匹配,Oracle的執行(版本8-B123)返回相同的字符串對象,而GNU類路徑(0.95版本),而不管返回一個新的字符串對象。

如果你能找到任何需要String.replace(CharSequence, CharSequence)返回時,沒有找到匹配的相同String對象的文檔的任何條款,請發表評論。

龍答案

下面長的答案是要表明,不同的實現可能會或可能不會進行優化,其中沒有找到匹配的情況。

讓我們看看Oracle的實現和GNU Classpath的實現方法String.replace(CharSequence, CharSequence)

GNU Classpath的

注意:這是在撰寫時是正確的。雖然鏈接未來可能不會改變,但鏈接內容可能會更改爲較新版本的GNU Classpath,並可能與以下引用的內容不同步。如果更改影響正確性,請發表評論。

讓我們看看GNU Classpath的實現String.replace(CharSequence, CharSequence)(引用版本0.95)。我們檢查StringBuilder.toString()的源代碼。由於這決定了返回值,如果StringBuilder.toString()複製緩衝區,那麼我們不需要進一步檢查上面的任何代碼。

/** 
* Convert this <code>StringBuilder</code> to a <code>String</code>. The 
* String is composed of the characters currently in this StringBuilder. Note 
* that the result is a copy, and that future modifications to this buffer 
* do not affect the String. 
* 
* @return the characters in this StringBuilder 
*/ 

public String toString() 
{ 
    return new String(this); 
} 

如果文檔無法說服您,請按照String的構造函數進行操作。最終調用非公開構造函數String(char[], int, int, boolean),將boolean dont_copy設置爲false,這意味着新的String必須複製緩衝區。

589: public String(StringBuilder buffer) 
590: { 
591:  this(buffer.value, 0, buffer.count); 
592: } 

245: public String(char[] data, int offset, int count) 
246: { 
247:  this(data, offset, count, false); 
248: } 

594: /** 
595: * Special constructor which can share an array when safe to do so. 
596: * 
597: * @param data the characters to copy 
598: * @param offset the location to start from 
599: * @param count the number of characters to use 
600: * @param dont_copy true if the array is trusted, and need not be copied 
601: * @throws NullPointerException if chars is null 
602: * @throws StringIndexOutOfBoundsException if bounds check fails 
603: */ 
604: String(char[] data, int offset, int count, boolean dont_copy) 
605: { 
606:  if (offset < 0) 
607:   throw new StringIndexOutOfBoundsException("offset: " + offset); 
608:  if (count < 0) 
609:   throw new StringIndexOutOfBoundsException("count: " + count); 
610:  // equivalent to: offset + count < 0 || offset + count > data.length 
611:  if (data.length - offset < count) 
612:   throw new StringIndexOutOfBoundsException("offset + count: " 
613:             + (offset + count)); 
614:  if (dont_copy) 
615:  { 
616:   value = data; 
617:   this.offset = offset; 
618:  } 
619:  else 
620:  { 
621:   value = new char[count]; 
622:   VMSystem.arraycopy(data, offset, value, 0, count); 
623:   this.offset = 0; 
624:  } 
625:  this.count = count; 
626: } 

這些證據表明,GNU Classpath的的實施String.replace(CharSequence, CharSequence)不返回相同的字符串。

甲骨文

在Oracle的實現String.replace(CharSequence, CharSequence)(版本報價8-B123),該方法利用Pattern類做了更換。

public String replace(CharSequence target, CharSequence replacement) { 
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
      this).replaceAll(Matcher.quoteReplacement(replacement.toString())); 
} 

Matcher.replaceAll(String)通話toString()功能上CharSequence並返回它的時候沒有找到匹配:

public String replaceAll(String replacement) { 
    reset(); 
    boolean result = find(); 
    if (result) { 
     StringBuffer sb = new StringBuffer(); 
     do { 
      appendReplacement(sb, replacement); 
      result = find(); 
     } while (result); 
     appendTail(sb); 
     return sb.toString(); 
    } 
    return text.toString(); 
} 

String實現CharSequence接口,並且因爲字符串通過自己進入Matcher,讓我們看看String.toString

public String toString() { 
    return this; 
} 

由此,我們可以得出結論:當沒有找到匹配項時,Oracle的實現返回相同的字符串。

+0

有趣的觀察。 +1 :) – TheLostMind 2014-11-05 12:28:15

2

我還沒有找到一個明確的答案(從文檔),但我想這一點在Oracle JRE7,發現replace返回參考相同的字符串

這裏是我用於測試的代碼:

public class NoReplace { 
    public static void main(String[]args) { 
     String a = "hello"; 

     /* Test: replacement with no match */ 
     String b = a.replace("X", "H"); 
     /* a and b are still the same string? */ 
     System.out.println(b == a); // true 

     /* Sanity: replacement WITH a match */ 
     String c = a.replace("h", "H"); 
     /* a and c are still the same string? */ 
     System.out.println(c == a); // false 
    } 
} 

但我很希望看到的replace VS contains一些基準,以肯定知道如果有任何優勢。

1

確定..在Java 8。這是當你調用myString.replace()會發生什麼。

public String replace(CharSequence target, CharSequence replacement) { 
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
      this).replaceAll(Matcher.quoteReplacement(replacement.toString())); 
} 

Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this) 目標串被編譯爲文字圖案。並且通過將調用stringInstance傳遞給它來調用matcher()

現在匹配()方法將在這裏返回一個新的匹配。只要注意了matchertext領域將是當前對象(this)即在其replace()被稱爲String對象。

接下來,在replaceAll()我們有下面的代碼: boolean result = find();

public String replaceAll(String replacement) { 
    reset(); 
    boolean result = find(); --> returns false. 
    if (result) { 
     StringBuffer sb = new StringBuffer(); 
     do { 
      appendReplacement(sb, replacement); 
      result = find(); 
     } while (result); 
     appendTail(sb); 
     return sb.toString(); 
    } 
    return text.toString(); --> same String 
} 
    if `find()` returns false, then ,matcher.text is returned which is the original String 
+0

很酷。你有沒有參考Java規範? – ColBeseder 2014-11-05 06:35:38

+0

@ColBeseder - [here](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char))是Oracle doc的參考。 – TheLostMind 2014-11-05 06:36:44

+3

這是對替換(char,char)的引用。這不是問題中使用的方法。替換的javaDoc(CharSequence,CharSequence)在這種情況下沒有指定所需的行爲。 – Eran 2014-11-05 06:39:15

相關問題