假设您有以下字符串:
cat dog fish dog fish cat
您希望将所有cats
替换为dogs
,将所有dogs
替换为fish
,将所有fish
替换为cats
。直观地说,预期的结果是:
dog fish cat fish cat dog
如果你尝试使用replaceAll()
循环的显而易见的解决方案,你会得到:
cat dog fish dog fish cat
dog dog fish dog fish dog
fish fish fish fish fish fish
cat cat cat cat cat cat
显然,这不是预期的结果。那么最简单的方法是什么?我可以和Pattern
和Matcher
(以及很多Pattern.quote()
和Matcher.quoteReplacement()
)一起拼凑一些东西,但我拒绝相信我是第一个遇到这个问题的人并且没有库函数来解决它。
(FWIW,实际案例有点复杂,不涉及直接交换。)
答案 0 :(得分:8)
apache commons中似乎StringUtils.replaceEach可以满足您的需求:
StringUtils.replaceEach("abcdeab", new String[]{"ab", "cd"}, new String[]{"cd", "ab"});
// returns "cdabecd"
请注意,上述链接中的文档似乎有误。有关详细信息,请参阅下面的评论。
答案 1 :(得分:7)
String rep = str.replace("cat","§1§").replace("dog","§2§")
.replace("fish","§3§").replace("§1§","dog")
.replace("§2§","fish").replace("§3§","cat");
丑陋低效,但是很有效。
好的,这是一个更复杂和通用的版本。我更喜欢使用正则表达式而不是扫描仪。这样我可以替换任意字符串,而不仅仅是单词(可以更好或更差)。无论如何,这里是:
public static String replace(
final String input, final Map<String, String> replacements) {
if (input == null || "".equals(input) || replacements == null
|| replacements.isEmpty()) {
return input;
}
StringBuilder regexBuilder = new StringBuilder();
Iterator<String> it = replacements.keySet().iterator();
regexBuilder.append(Pattern.quote(it.next()));
while (it.hasNext()) {
regexBuilder.append('|').append(Pattern.quote(it.next()));
}
Matcher matcher = Pattern.compile(regexBuilder.toString()).matcher(input);
StringBuffer out = new StringBuffer(input.length() + (input.length() / 10));
while (matcher.find()) {
matcher.appendReplacement(out, replacements.get(matcher.group()));
}
matcher.appendTail(out);
return out.toString();
}
测试代码:
System.out.println(replace("cat dog fish dog fish cat",
ImmutableMap.of("cat", "dog", "dog", "fish", "fish", "cat")));
输出:
狗鱼猫猫猫狗
显然这个解决方案只对许多替代品有意义,否则这是一个巨大的矫枉过正。
答案 2 :(得分:4)
我会创建一个StringBuilder然后解析文本 一次 ,一次解析一个单词,转移未更改的单词或更改单词。我不会像你建议的那样为每次交换解析它。
所以不要做类似的事情:
// pseudocode
text is new text swapping cat with dog
text is new text swapping dog with fish
text is new text swapping fish with cat
我会做
for each word in text
if word is cat, swap with dog
if word is dog, swap with fish
if word is fish, swap with cat
transfer new word (or unchanged word) into StringBuilder.
我可能会为此创建一个swap(...)方法,并使用HashMap进行交换。
例如
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class SwapWords {
private static Map<String, String> myMap = new HashMap<String, String>();
public static void main(String[] args) {
// this would really be loaded using a file such as a text file or xml
// or even a database:
myMap.put("cat", "dog");
myMap.put("dog", "fish");
myMap.put("fish", "dog");
String testString = "cat dog fish dog fish cat";
StringBuilder sb = new StringBuilder();
Scanner testScanner = new Scanner(testString);
while (testScanner.hasNext()) {
String text = testScanner.next();
text = myMap.get(text) == null ? text : myMap.get(text);
sb.append(text + " ");
}
System.out.println(sb.toString().trim());
}
}
答案 3 :(得分:0)
public class myreplase {
public Map<String, String> replase;
public myreplase() {
replase = new HashMap<String, String>();
replase.put("a", "Apple");
replase.put("b", "Banana");
replase.put("c", "Cantalope");
replase.put("d", "Date");
String word = "a b c d a b c d";
String ss = "";
Iterator<String> i = replase.keySet().iterator();
while (i.hasNext()) {
ss += i.next();
if (i.hasNext()) {
ss += "|";
}
}
Pattern pattern = Pattern.compile(ss);
StringBuilder buffer = new StringBuilder();
for (int j = 0, k = 1; j < word.length(); j++,k++) {
String s = word.substring(j, k);
Matcher matcher = pattern.matcher(s);
if (matcher.find()) {
buffer.append(replase.get(s));
} else {
buffer.append(s);
}
}
System.out.println(buffer.toString());
}
public static void main(String[] args) {
new myreplase();
}
}
输出: - Apple Banana Cantalope Date Apple Banana Cantalope Date
答案 4 :(得分:0)
这是一种无需使用正则表达式的方法。
我注意到,每次将字符串a
的一部分替换为b
时,b
将始终是最终字符串的一部分。因此,从此以后,您就可以忽略字符串中的b
。
不仅如此,在将a
替换为b
之后,还有一个“空格”。在应该b
的位置上无法进行任何替换。
这些动作加起来看起来很像split
。 split
增大值(在字符串之间形成“空格”),对数组中的每个字符串进行进一步的替换,然后将它们重新连接起来。
例如:
// Original
"cat dog fish dog fish cat"
// Replace cat with dog
{"", "dog fish dog fish", ""}.join("dog")
// Replace dog with fish
{
"",
{"", " fish ", " fish"}.join("fish")
""
}.join("dog")
// Replace fish with cat
{
"",
{
"",
{" ", " "}.join("cat"),
{" ", ""}.join("cat")
}.join("fish")
""
}.join("dog")
到目前为止(对我而言)最直观的方法是递归执行:
public static String replaceWithJointMap(String s, Map<String, String> map) {
// Base case
if (map.size() == 0) {
return s;
}
// Get some value in the map to replace
Map.Entry pair = map.entrySet().iterator().next();
String replaceFrom = (String) pair.getKey();
String replaceTo = (String) pair.getValue();
// Split the current string with the replaceFrom string
// Use split with -1 so that trailing empty strings are included
String[] splitString = s.split(Pattern.quote(replaceFrom), -1);
// Apply replacements for each of the strings in the splitString
HashMap<String, String> replacementsLeft = new HashMap<>(map);
replacementsLeft.remove(replaceFrom);
for (int i=0; i<splitString.length; i++) {
splitString[i] = replaceWithJointMap(splitString[i], replacementsLeft);
}
// Join back with the current replacements
return String.join(replaceTo, splitString);
}
我认为这不是很有效。