一次替换多个子串

假设我有一个文件,其中包含一些文字。 其中有子字符串,如“substr1”,“substr2”,“substr3”等。 我需要用其他一些文本替换所有这些子串,例如“repl1”,“repl2”,“repl3”。 在Python中,我会创建一个这样的字典:

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

并创建用’|’连接键的模式,然后用re.sub函数替换。 在Java中是否有类似的简单方法?

这就是你的Python建议转换为Java的方式:

 Map replacements = new HashMap() {{ 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 

这种方法可以进行同步 (即“立即”)替换。 即,如果你碰巧有

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

然后这种方法会给出"ab" -> "bc"而不是答案,表明你应该链接几个调用来replacereplace会给出"cc"调用。


(如果您通过这种方法概括地以编程方式创建正则表达式,请确保Pattern.quote每个单独的搜索词和Matcher.quoteReplacement每个替换词。)

Apache Commons Lang项目中的StringUtils.replaceEach ,但它适用于Strings。

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

首先,问题的演示:

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

这是为了取代cats => dog and dogs => 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是Ham,而Ham是Hamster

如果我们使用simultaneousReplace而不是simultaneousReplaceLongest ,则输出将具有“HamScript”而不是“Hamster”:)

请注意,上述方法区分大小写。 如果您需要不区分大小写的版本,则可以轻松修改上述内容,因为String.regionMatches可以使用ignoreCase参数。

  return yourString.replaceAll("substr1","relp1"). replaceAll("substr2","relp2"). replaceAll("substr3","relp3")