2011-10-05 145 views
8

說我有一個文件,其中包含一些文本。有「substr1」,「substr2」,「substr3」等子字符串。我需要用其他文本替換所有這些子字符串,如「repl1」,「repl2」,「repl3」。在Python中,我將創建一個這樣的解釋:立即替換多個子字符串

{ 
"substr1": "repl1", 
"substr2": "repl2", 
"substr3": "repl3" 
} 

和創建模式加入與鍵「|」,然後用re.sub功能替代。 在Java中是否有類似的簡單方法?

+0

相關主題 - http://stackoverflow.com/questions/2049528/java-best-way-for-string-find-and-replace – adatapost

回答

14

這是你的Python-建議如何轉換爲Java:

Map<String, String> replacements = new HashMap<String, String>() {{ 
    put("substr1", "repl1"); 
    put("substr2", "repl2"); 
    put("substr3", "repl3"); 
}}; 

String input = "lorem substr1 ipsum substr2 dolor substr3 amet"; 

// create the pattern joining the keys with '|' 
String regexp = "substr1|substr2|substr3"; 

StringBuffer sb = new StringBuffer(); 
Pattern p = Pattern.compile(regexp); 
Matcher m = p.matcher(input); 

while (m.find()) 
    m.appendReplacement(sb, replacements.get(m.group())); 
m.appendTail(sb); 


System.out.println(sb.toString()); // lorem repl1 ipsum repl2 dolor repl3 amet 

這種方法做了simultanious(即 「一次」)替換。即,如果你碰巧有

"a" -> "b" 
"b" -> "c" 

那麼這種做法將給"a b" -> "b c",而不是答案建議你應該鏈多次打電話給replacereplaceAll這將使"c c"


(如果推廣這種方法以編程方式創建的正則表達式,請確保您Pattern.quote每個單獨的搜索詞和Matcher.quoteReplacement每個替換詞。)

+0

這種方法與StringUtils.replaceEach有何不同?或者replaceEach與replaceAll相同? –

+0

這種方法更通用,因爲您可以提供任意替換函數(查看'm.appendReplacement'行)。其次,它並不要求你爲了一個字符串操作例程而包含一個第三方庫。 (如果你已經依賴於Apache Commons,或者完全不用其他的依賴關係,那麼就使用'replaceEach'方法。) – aioobe

+0

(不,'replaceEach'與'replaceAll'不一樣''replaceAll'只是'替換'的正則表達式版本。) – aioobe

2
yourString.replace("substr1", "repl1") 
      .replace("substr2", "repl2") 
      .replace("substr3", "repl3"); 
+4

+1 ...雖然這不是「全部一次」。如果這個例子不同,比如說''a「 - >」b「'和'」b「 - >」c「',那麼結果中就不會有'b',即使有'a'在輸入中。 – aioobe

+0

看起來相當難看,不過謝謝:) –

+0

@aioobe:'StringUtils.replaceEach()'處理這個問題。 – palacsint

-1
return yourString.replaceAll("substr1","relp1"). 
        replaceAll("substr2","relp2"). 
        replaceAll("substr3","relp3") 
+0

-1。這不是全部,並且不必要地使用正則表達式方法(replaceAll)而不是普通的String方法(replace)。 – Boann

1

首先,問題的演示:

String s = "I have three cats and two dogs."; 
s = s.replace("cats", "dogs") 
    .replace("dogs", "budgies"); 
System.out.println(s); 

這是爲了取代貓=>狗和狗=> budgies,但順序替換操作的結果前一個r所以不幸的輸出是:

我有三budgies和兩budgies。

這是我的同步替換方法的實現。這很容易使用String.regionMatches寫:

public static String simultaneousReplace(String subject, String... pairs) { 
    if (pairs.length % 2 != 0) throw new IllegalArgumentException(
     "Strings to find and replace are not paired."); 
    StringBuilder sb = new StringBuilder(); 
    int numPairs = pairs.length/2; 
    outer: 
    for (int i = 0; i < subject.length(); i++) { 
     for (int j = 0; j < numPairs; j++) { 
      String find = pairs[j * 2]; 
      if (subject.regionMatches(i, find, 0, find.length())) { 
       sb.append(pairs[j * 2 + 1]); 
       i += find.length() - 1; 
       continue outer; 
      } 
     } 
     sb.append(subject.charAt(i)); 
    } 
    return sb.toString(); 
} 

測試:

String s = "I have three cats and two dogs."; 
s = simultaneousReplace(s, 
    "cats", "dogs", 
    "dogs", "budgies"); 
System.out.println(s); 

輸出:

我有三條狗和兩個虎皮鸚鵡。

此外,它在進行同步替換時有時很有用,以確保查找最長匹配。 (例如,PHP的strtr函數執行此操作。)這是我的實現:

public static String simultaneousReplaceLongest(String subject, String... pairs) { 
    if (pairs.length % 2 != 0) throw new IllegalArgumentException(
     "Strings to find and replace are not paired."); 
    StringBuilder sb = new StringBuilder(); 
    int numPairs = pairs.length/2; 
    for (int i = 0; i < subject.length(); i++) { 
     int longestMatchIndex = -1; 
     int longestMatchLength = -1; 
     for (int j = 0; j < numPairs; j++) { 
      String find = pairs[j * 2]; 
      if (subject.regionMatches(i, find, 0, find.length())) { 
       if (find.length() > longestMatchLength) { 
        longestMatchIndex = j; 
        longestMatchLength = find.length(); 
       } 
      } 
     } 
     if (longestMatchIndex >= 0) { 
      sb.append(pairs[longestMatchIndex * 2 + 1]); 
      i += longestMatchLength - 1; 
     } else { 
      sb.append(subject.charAt(i)); 
     } 
    } 
    return sb.toString(); 
} 

爲什麼你需要這個?舉例如下:

String truth = "Java is to JavaScript"; 
truth += " as " + simultaneousReplaceLongest(truth, 
    "Java", "Ham", 
    "JavaScript", "Hamster"); 
System.out.println(truth); 

輸出:

Java是對JavaScript作爲火腿是倉鼠

如果我們使用的simultaneousReplace代替simultaneousReplaceLongest,輸出將不得不 「HamScript」而不是「倉鼠」:)

請注意,上述方法是區分大小寫的。如果您需要不區分大小寫的版本,則可以輕鬆修改上述內容,因爲String.regionMatches可以使用ignoreCase參數。