In primo luogo, una dimostrazione del problema:
String s = "I have three cats and two dogs.";
s = s.replace("cats", "dogs")
.replace("dogs", "budgies");
System.out.println(s);
Questo è destinato a sostituire gatti => cani e cani => pappagallini, ma la sostituzione sequenziale opera sul risultato della precedente r eplacement, quindi l'uscita sfortunata è:
Ho tre panieri e due pappagallini.
Ecco la mia implementazione di un metodo di sostituzione simultanea. E 'facile scrivere utilizzando 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);
uscita:
ho tre cani e due pappagallini.
Inoltre, a volte è utile quando si effettua la sostituzione simultanea, per assicurarsi di cercare la corrispondenza più lunga. (La funzione PHP strtr
fa questo, per esempio.) Ecco la mia implementazione per questo:
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();
}
Perché avresti bisogno di questo? Esempio segue:
String truth = "Java is to JavaScript";
truth += " as " + simultaneousReplaceLongest(truth,
"Java", "Ham",
"JavaScript", "Hamster");
System.out.println(truth);
uscita:
Java è quello di JavaScript come Ham è quello di Hamster
Se avessimo usato simultaneousReplace
al posto del simultaneousReplaceLongest
, l'uscita avrebbe avuto "HamScript" invece di "Hamster" :)
Si noti che i metodi di cui sopra fanno distinzione tra maiuscole e minuscole. Se hai bisogno di versioni maiuscole e minuscole è facile modificare quanto sopra perché String.regionMatches
può prendere un parametro ignoreCase
.
Thread correlato - http://stackoverflow.com/questions/2049528/java-best-way-for-string-find-and-replace – adatapost