java 一次替换多个子串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7661460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace multiple substrings at once
提问by Andrii Yurchuk
Say I have a file, that contains some text. There are substrings like "substr1", "substr2", "substr3" etc. in it. I need to replace all of those substrings with some other text, like "repl1", "repl2", "repl3". In Python, I would create a dictionary like this:
假设我有一个文件,其中包含一些文本。其中有“substr1”、“substr2”、“substr3”等子字符串。我需要用其他一些文本替换所有这些子字符串,例如“repl1”、“repl2”、“repl3”。在 Python 中,我会创建一个这样的字典:
{
"substr1": "repl1",
"substr2": "repl2",
"substr3": "repl3"
}
and create the pattern joining the keys with '|', then replace with re.sub
function.
Is there a similar simple way to do this in Java?
并创建用“|”连接键的模式,然后用re.sub
函数替换。在 Java 中是否有类似的简单方法可以做到这一点?
回答by aioobe
This is how your Python-suggestion translates to Java:
这就是您的 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
This approach does a simultanious(i.e. "at once") replacement. I.e., if you happened to have
这种方法进行同时(即“立即”)替换。也就是说,如果你碰巧有
"a" -> "b"
"b" -> "c"
then this approach would give "a b" -> "b c"
as opposed to the answers suggesting you should chain several calls to replace
or replaceAll
which would give "c c"
.
那么这种方法会给出"a b" -> "b c"
,而不是建议你应该将多个调用链接到replace
或replaceAll
哪个会给出的答案"c c"
。
(If you generalize this approach to create the regexp programatically, make sure you Pattern.quote
each individual search word and Matcher.quoteReplacement
each replacement word.)
(如果您将这种方法概括为以编程方式创建正则表达式,请确保您使用Pattern.quote
每个单独的搜索词和Matcher.quoteReplacement
每个替换词。)
回答by palacsint
StringUtils.replaceEach
in the Apache Commons Lang project, but it works on Strings.
回答by Eng.Fouad
yourString.replace("substr1", "repl1")
.replace("substr2", "repl2")
.replace("substr3", "repl3");
回答by Boann
First, a demonstration of the problem:
先演示一下问题:
String s = "I have three cats and two dogs.";
s = s.replace("cats", "dogs")
.replace("dogs", "budgies");
System.out.println(s);
This is intended to replace cats => dogs and dogs => budgies, but the sequential replacement operates on the result of the previous replacement, so the unfortunate output is:
这是为了替换猫 => 狗和狗 => budgies,但是顺序替换操作的是前一个替换的结果,所以不幸的输出是:
I have three budgies and two budgies.
我有三只鹦鹉和两只鹦鹉。
Here's my implementation of a simultaneous replacement method. It's easy to write using String.regionMatches
:
这是我对同时替换方法的实现。使用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();
}
Testing:
测试:
String s = "I have three cats and two dogs.";
s = simultaneousReplace(s,
"cats", "dogs",
"dogs", "budgies");
System.out.println(s);
Output:
输出:
I have three dogs and two budgies.
我有三只狗和两只鹦鹉。
Additionally, it is sometimes useful when doing simultaneous replacement, to make sure to look for the longest match. (PHP's strtr
function does this, for example.) Here is my implementation for that:
此外,有时在进行同时替换时很有用,以确保寻找最长的匹配。(strtr
例如,PHP 的函数就是这样做的。)这是我的实现:
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();
}
Why would you need this? Example follows:
你为什么需要这个?示例如下:
String truth = "Java is to JavaScript";
truth += " as " + simultaneousReplaceLongest(truth,
"Java", "Ham",
"JavaScript", "Hamster");
System.out.println(truth);
Output:
输出:
Java is to JavaScript as Ham is to Hamster
Java 之于 JavaScript 就像 Ham 之于仓鼠
If we had used simultaneousReplace
instead of simultaneousReplaceLongest
, the output would have had "HamScript" instead of "Hamster" :)
如果我们使用了simultaneousReplace
而不是simultaneousReplaceLongest
,输出将有“HamScript”而不是“Hamster”:)
Note that the above methods are case-sensitive. If you need case-insensitive versions it is easy to modify the above because String.regionMatches
can take an ignoreCase
parameter.
请注意,上述方法区分大小写。如果您需要不区分大小写的版本,可以很容易地修改上述内容,因为String.regionMatches
可以使用ignoreCase
参数。
回答by Balconsky
return yourString.replaceAll("substr1","relp1").
replaceAll("substr2","relp2").
replaceAll("substr3","relp3")