2011-10-05 146 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参数。