Disons que j'ai le code suivant:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("foo", Word1);
story = story.replace("bar", Word2);
Une fois ce code exécuté, la valeur de story
sera "Once upon a time, there was a foo and a foo."
Un problème similaire se produit si je les ai remplacés dans l'ordre inverse:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("bar", Word2);
story = story.replace("foo", Word1);
La valeur de story
sera "Once upon a time, there was a bar and a bar."
Mon but est de transformer story
en "Once upon a time, there was a bar and a foo."
Comment pourrais-je accomplir cela?
Utilisez la méthode replaceEach()
de Apache Commons StringUtils :
StringUtils.replaceEach(story, new String[]{"foo", "bar"}, new String[]{"bar", "foo"})
Vous pouvez essayer quelque chose comme ça en utilisant Matcher#appendReplacement
et Matcher#appendTail
:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
Pattern p = Pattern.compile("foo|bar");
Matcher m = p.matcher(story);
StringBuffer sb = new StringBuffer();
while (m.find()) {
/* do the swap... */
switch (m.group()) {
case "foo":
m.appendReplacement(sb, Word1);
break;
case "bar":
m.appendReplacement(sb, Word2);
break;
default:
/* error */
break;
}
}
m.appendTail(sb);
System.out.println(sb.toString());
Il était une fois un bar et un foo.
Ce n'est pas un problème facile. Et plus vous avez de paramètres de recherche-remplacement, plus cela devient délicat. Vous avez plusieurs options, dispersées sur la palette de laide-élégant, efficace-gaspiller:
Utilisation StringUtils.replaceEach
de Apache Commons comme @ AlanHay recommandé. C'est une bonne option si vous êtes libre d'ajouter de nouvelles dépendances dans votre projet. Vous pourriez avoir de la chance: la dépendance pourrait déjà être incluse dans votre projet
Utilisez un espace réservé temporaire comme @ Jeroen suggéré et effectuez le remplacement en 2 étapes:
Ce n’est pas une bonne approche pour plusieurs raisons: il faut s’assurer que les balises utilisées lors de la première étape sont vraiment uniques; il effectue plus d'opérations de remplacement de chaînes que nécessaire
Construisez une expression rationnelle à partir de tous les modèles et utilisez la méthode avec Matcher
et StringBuffer
comme suggéré par @ arshajii . Ce n'est pas terrible, mais pas terrible non plus, car la construction de la regex est une sorte de hackish et implique StringBuffer
qui s'est démodé il y a quelque temps en faveur de StringBuilder
.
Utilisez une solution récursive proposée par @ mjolka , en scindant la chaîne au niveau des modèles correspondants et en effectuant une récurrence sur les segments restants. C'est une bonne solution, compacte et assez élégante. Sa faiblesse réside dans le nombre potentiellement important d'opérations de sous-chaîne et de concaténation, ainsi que dans les limites de taille de pile qui s'appliquent à toutes les solutions récursives.
Divisez le texte en mots et utilisez Java 8 flux pour effectuer les remplacements avec élégance comme @ msandiford suggéré, mais cela ne fonctionne bien entendu que si vous êtes en mesure de fractionner Word les limites, ce qui le rend pas approprié comme une solution générale
Voici ma version, basée sur des idées empruntées à implémentation d'Apache . Ce n'est ni simple ni élégant, mais cela fonctionne et devrait être relativement efficace, sans étapes inutiles. En résumé, cela fonctionne comme suit: trouvez de manière répétée le prochain motif de recherche correspondant dans le texte et utilisez un StringBuilder
pour accumuler les segments non appariés et les remplacements.
public static String replaceEach(String text, String[] searchList, String[] replacementList) {
// TODO: throw new IllegalArgumentException() if any param doesn't make sense
//validateParams(text, searchList, replacementList);
SearchTracker tracker = new SearchTracker(text, searchList, replacementList);
if (!tracker.hasNextMatch(0)) {
return text;
}
StringBuilder buf = new StringBuilder(text.length() * 2);
int start = 0;
do {
SearchTracker.MatchInfo matchInfo = tracker.matchInfo;
int textIndex = matchInfo.textIndex;
String pattern = matchInfo.pattern;
String replacement = matchInfo.replacement;
buf.append(text.substring(start, textIndex));
buf.append(replacement);
start = textIndex + pattern.length();
} while (tracker.hasNextMatch(start));
return buf.append(text.substring(start)).toString();
}
private static class SearchTracker {
private final String text;
private final Map<String, String> patternToReplacement = new HashMap<>();
private final Set<String> pendingPatterns = new HashSet<>();
private MatchInfo matchInfo = null;
private static class MatchInfo {
private final String pattern;
private final String replacement;
private final int textIndex;
private MatchInfo(String pattern, String replacement, int textIndex) {
this.pattern = pattern;
this.replacement = replacement;
this.textIndex = textIndex;
}
}
private SearchTracker(String text, String[] searchList, String[] replacementList) {
this.text = text;
for (int i = 0; i < searchList.length; ++i) {
String pattern = searchList[i];
patternToReplacement.put(pattern, replacementList[i]);
pendingPatterns.add(pattern);
}
}
boolean hasNextMatch(int start) {
int textIndex = -1;
String nextPattern = null;
for (String pattern : new ArrayList<>(pendingPatterns)) {
int matchIndex = text.indexOf(pattern, start);
if (matchIndex == -1) {
pendingPatterns.remove(pattern);
} else {
if (textIndex == -1 || matchIndex < textIndex) {
textIndex = matchIndex;
nextPattern = pattern;
}
}
}
if (nextPattern != null) {
matchInfo = new MatchInfo(nextPattern, patternToReplacement.get(nextPattern), textIndex);
return true;
}
return false;
}
}
Tests unitaires:
@Test
public void testSingleExact() {
assertEquals("bar", StringUtils.replaceEach("foo", new String[]{"foo"}, new String[]{"bar"}));
}
@Test
public void testReplaceTwice() {
assertEquals("barbar", StringUtils.replaceEach("foofoo", new String[]{"foo"}, new String[]{"bar"}));
}
@Test
public void testReplaceTwoPatterns() {
assertEquals("barbaz", StringUtils.replaceEach("foobar",
new String[]{"foo", "bar"},
new String[]{"bar", "baz"}));
}
@Test
public void testReplaceNone() {
assertEquals("foofoo", StringUtils.replaceEach("foofoo", new String[]{"x"}, new String[]{"bar"}));
}
@Test
public void testStory() {
assertEquals("Once upon a foo, there was a bar and a baz, and another bar and a cat.",
StringUtils.replaceEach("Once upon a baz, there was a foo and a bar, and another foo and a cat.",
new String[]{"foo", "bar", "baz"},
new String[]{"bar", "baz", "foo"})
);
}
Recherchez le premier mot à remplacer. Si c'est dans la chaîne, récidive sur la partie de la chaîne avant l'occurrence et sur la partie de la chaîne après l'occurrence.
Sinon, continuez avec le prochain mot à remplacer.
Une implémentation naïve pourrait ressembler à ceci
public static String replaceAll(String input, String[] search, String[] replace) {
return replaceAll(input, search, replace, 0);
}
private static String replaceAll(String input, String[] search, String[] replace, int i) {
if (i == search.length) {
return input;
}
int j = input.indexOf(search[i]);
if (j == -1) {
return replaceAll(input, search, replace, i + 1);
}
return replaceAll(input.substring(0, j), search, replace, i + 1) +
replace[i] +
replaceAll(input.substring(j + search[i].length()), search, replace, i);
}
Exemple d'utilisation:
String input = "Once upon a baz, there was a foo and a bar.";
String[] search = new String[] { "foo", "bar", "baz" };
String[] replace = new String[] { "bar", "baz", "foo" };
System.out.println(replaceAll(input, search, replace));
Sortie:
Once upon a foo, there was a bar and a baz.
Une version moins naïve:
public static String replaceAll(String input, String[] search, String[] replace) {
StringBuilder sb = new StringBuilder();
replaceAll(sb, input, 0, input.length(), search, replace, 0);
return sb.toString();
}
private static void replaceAll(StringBuilder sb, String input, int start, int end, String[] search, String[] replace, int i) {
while (i < search.length && start < end) {
int j = indexOf(input, search[i], start, end);
if (j == -1) {
i++;
} else {
replaceAll(sb, input, start, j, search, replace, i + 1);
sb.append(replace[i]);
start = j + search[i].length();
}
}
sb.append(input, start, end);
}
Malheureusement, la String
de Java n'a pas de méthode indexOf(String str, int fromIndex, int toIndex)
. J'ai omis la mise en œuvre de indexOf
ici car je ne suis pas sûr que ce soit correct, mais vous pouvez le trouver sur ideone , avec quelques timings approximatifs des différentes solutions publiées ici.
One-Liner in Java 8:
story = Pattern
.compile(String.format("(?<=%1$s)|(?=%1$s)", "foo|bar"))
.splitAsStream(story)
.map(w -> ImmutableMap.of("bar", "foo", "foo", "bar").getOrDefault(w, w))
.collect(Collectors.joining());
?<=
, ?=
): http://www.regular-expressions.info/lookaround.htmlVoici une possibilité de Java 8 flux qui pourrait être intéressante pour certains:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
// Map is from untranslated Word to translated Word
Map<String, String> wordMap = new HashMap<>();
wordMap.put(Word1, Word2);
wordMap.put(Word2, Word1);
// Split on Word boundaries so we retain whitespace.
String translated = Arrays.stream(story.split("\\b"))
.map(w -> wordMap.getOrDefault(w, w))
.collect(Collectors.joining());
System.out.println(translated);
Voici une approximation du même algorithme dans Java 7:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
// Map is from untranslated Word to translated Word
Map<String, String> wordMap = new HashMap<>();
wordMap.put(Word1, Word2);
wordMap.put(Word2, Word1);
// Split on Word boundaries so we retain whitespace.
StringBuilder translated = new StringBuilder();
for (String w : story.split("\\b"))
{
String tw = wordMap.get(w);
translated.append(tw != null ? tw : w);
}
System.out.println(translated);
Si vous souhaitez remplacer des mots dans une phrase séparés par un espace, comme indiqué dans votre exemple, vous pouvez utiliser cet algorithme simple.
Si la division de l'espace n'est pas acceptable, vous pouvez suivre cet algorithme alternatif. Vous devez d'abord utiliser la chaîne la plus longue. Si les chaînes sont foo et imbécile, vous devez utiliser imbécile en premier, puis foo.
Voici une réponse moins compliquée en utilisant Map.
private static String replaceEach(String str,Map<String, String> map) {
Object[] keys = map.keySet().toArray();
for(int x = 0 ; x < keys.length ; x ++ ) {
str = str.replace((String) keys[x],"%"+x);
}
for(int x = 0 ; x < keys.length ; x ++) {
str = str.replace("%"+x,map.get(keys[x]));
}
return str;
}
Et la méthode s'appelle
Map<String, String> replaceStr = new HashMap<>();
replaceStr.put("Raffy","awesome");
replaceStr.put("awesome","Raffy");
String replaced = replaceEach("Raffy is awesome, awesome awesome is Raffy Raffy", replaceStr);
La sortie est: génial c'est Raffy, Raffy Raffy est génial génial
Cela fonctionne et est simple:
public String replaceBoth(String text, String token1, String token2) {
return text.replace(token1, "\ufdd0").replace(token2, token1).replace("\ufdd0", token2);
}
Vous l'utilisez comme ceci:
replaceBoth("Once upon a time, there was a foo and a bar.", "foo", "bar");
Remarque: cela compte sur les chaînes ne contenant pas le caractère \ufdd0
, qui est un caractère en permanence réservé à l'usage interne par Unicode (Voir http://www.unicode.org/faq/private_use.html ):
Je ne pense pas que ce soit nécessaire, mais si vous voulez être absolument en sécurité, vous pouvez utiliser:
public String replaceBoth(String text, String token1, String token2) {
if (text.contains("\ufdd0") || token1.contains("\ufdd0") || token2.contains("\ufdd0")) throw new IllegalArgumentException("Invalid character.");
return text.replace(token1, "\ufdd0").replace(token2, token1).replace("\ufdd0", token2);
}
Vous pouvez atteindre votre objectif avec le bloc de code suivant:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, in a foo, there was a foo and a bar.";
story = String.format(story.replace(Word1, "%1$s").replace(Word2, "%2$s"),
Word2, Word1);
Il remplace les mots indépendamment de l'ordre. Vous pouvez étendre ce principe à une méthode utilitaire, telle que:
private static String replace(String source, String[] targets, String[] replacements) throws IllegalArgumentException {
if (source == null) {
throw new IllegalArgumentException("The parameter \"source\" cannot be null.");
}
if (targets == null || replacements == null) {
throw new IllegalArgumentException("Neither parameters \"targets\" or \"replacements\" can be null.");
}
if (targets.length == 0 || targets.length != replacements.length) {
throw new IllegalArgumentException("The parameters \"targets\" and \"replacements\" must have at least one item and have the same length.");
}
String outputMask = source;
for (int i = 0; i < targets.length; i++) {
outputMask = outputMask.replace(targets[i], "%" + (i + 1) + "$s");
}
return String.format(outputMask, (Object[])replacements);
}
Qui serait consommé comme:
String story = "Once upon a time, in a foo, there was a foo and a bar.";
story = replace(story, new String[] { "bar", "foo" },
new String[] { "foo", "bar" }));
Si vous voulez pouvoir gérer plusieurs occurrences des chaînes de recherche à remplacer, vous pouvez le faire facilement en scindant la chaîne sur chaque terme de recherche, puis en la remplaçant. Voici un exemple:
String regex = Word1 + "|" + Word2;
String[] values = Pattern.compile(regex).split(story);
String result;
foreach subStr in values
{
subStr = subStr.replace(Word1, Word2);
subStr = subStr.replace(Word2, Word1);
result += subStr;
}
S'il n'y a qu'une seule occurrence de chacune des chaînes échangeables dans l'entrée, vous pouvez effectuer les opérations suivantes:
Avant de procéder à une quelconque substitution, obtenez les index des occurrences des mots. Après cela, nous ne remplaçons que le mot trouvé dans ces index, et non toutes les occurrences. Cette solution utilise StringBuilder
et ne produit pas d'intermédiaire String
comme String.replace()
.
Une chose à noter: si les mots échangeables ont des longueurs différentes, après le premier remplacement, le deuxième index pourrait changer (si le premier mot survient avant le second) exactement avec la différence des 2 longueurs. Donc, aligner le deuxième index garantira que cela fonctionne même si nous échangeons des mots de longueurs différentes.
public static String swap(String src, String s1, String s2) {
StringBuilder sb = new StringBuilder(src);
int i1 = src.indexOf(s1);
int i2 = src.indexOf(s2);
sb.replace(i1, i1 + s1.length(), s2); // Replace s1 with s2
// If s1 was before s2, idx2 might have changed after the replace
if (i1 < i2)
i2 += s2.length() - s1.length();
sb.replace(i2, i2 + s2.length(), s1); // Replace s2 with s1
return sb.toString();
}
De manière analogue au cas précédent, nous allons d'abord collecter les index (occurrences) des mots, mais dans ce cas, il s'agira d'une liste d'entiers pour chaque mot, et pas seulement d'un int
. Pour cela, nous allons utiliser la méthode d’utilité suivante:
public static List<Integer> occurrences(String src, String s) {
List<Integer> list = new ArrayList<>();
for (int idx = 0;;)
if ((idx = src.indexOf(s, idx)) >= 0) {
list.add(idx);
idx += s.length();
} else
return list;
}
Et en utilisant cela, nous remplacerons les mots par l’autre en diminuant l’index (ce qui nécessitera peut-être d’alterner entre les 2 mots échangeables), de sorte que nous n’aurons même pas à corriger les index après un remplacement:
public static String swapAll(String src, String s1, String s2) {
List<Integer> l1 = occurrences(src, s1), l2 = occurrences(src, s2);
StringBuilder sb = new StringBuilder(src);
// Replace occurrences by decreasing index, alternating between s1 and s2
for (int i1 = l1.size() - 1, i2 = l2.size() - 1; i1 >= 0 || i2 >= 0;) {
int idx1 = i1 < 0 ? -1 : l1.get(i1);
int idx2 = i2 < 0 ? -1 : l2.get(i2);
if (idx1 > idx2) { // Replace s1 with s2
sb.replace(idx1, idx1 + s1.length(), s2);
i1--;
} else { // Replace s2 with s1
sb.replace(idx2, idx2 + s2.length(), s1);
i2--;
}
}
return sb.toString();
}
Il est facile d'écrire une méthode pour faire cela en utilisant 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();
outer:
for (int i = 0; i < subject.length(); i++) {
for (int j = 0; j < pairs.length; j += 2) {
String find = pairs[j];
if (subject.regionMatches(i, find, 0, find.length())) {
sb.append(pairs[j + 1]);
i += find.length() - 1;
continue outer;
}
}
sb.append(subject.charAt(i));
}
return sb.toString();
}
Essai:
String s = "There are three cats and two dogs.";
s = simultaneousReplace(s,
"cats", "dogs",
"dogs", "budgies");
System.out.println(s);
Sortie:
Il y a trois chiens et deux perruches.
Cela n’est pas immédiatement évident, mais une fonction de ce type peut toujours dépendre de l’ordre dans lequel les remplacements sont spécifiés. Considérer:
String truth = "Java is to JavaScript";
truth += " as " + simultaneousReplace(truth,
"JavaScript", "Hamster",
"Java", "Ham");
System.out.println(truth);
Sortie:
Java est à JavaScript comme Ham est à Hamster
Mais inversez les remplacements:
truth += " as " + simultaneousReplace(truth,
"Java", "Ham",
"JavaScript", "Hamster");
Sortie:
Java est à JavaScript comme Ham est à HamScript
Oops! :)
Par conséquent, il est parfois utile de rechercher la correspondance la plus longue (comme le fait la fonction strtr
de PHP , par exemple). Cette version de la méthode fera cela:
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();
for (int i = 0; i < subject.length(); i++) {
int longestMatchIndex = -1;
int longestMatchLength = -1;
for (int j = 0; j < pairs.length; j += 2) {
String find = pairs[j];
if (subject.regionMatches(i, find, 0, find.length())) {
if (find.length() > longestMatchLength) {
longestMatchIndex = j;
longestMatchLength = find.length();
}
}
}
if (longestMatchIndex >= 0) {
sb.append(pairs[longestMatchIndex + 1]);
i += longestMatchLength - 1;
} else {
sb.append(subject.charAt(i));
}
}
return sb.toString();
}
Notez que les méthodes ci-dessus sont sensibles à la casse. Si vous avez besoin d'une version ne respectant pas la casse, il est facile de modifier ce qui précède car String.regionMatches
peut prendre un paramètre ignoreCase
.
Vous effectuez plusieurs opérations de recherche-remplacement sur l'entrée. Cela produira des résultats indésirables lorsque les chaînes de remplacement contiennent des chaînes de recherche. Prenons l'exemple foo-> bar, bar-foo, voici les résultats pour chaque itération:
Vous devez effectuer le remplacement en une itération sans revenir en arrière. Une solution de force brute est la suivante:
Une fonction telle que String.indexOfAny(String[]) -> int[]{index, whichString}
serait utile. Voici un exemple (pas le plus efficace):
private static String replaceEach(String str, String[] searchWords, String[] replaceWords) {
String ret = "";
while (str.length() > 0) {
int i;
for (i = 0; i < searchWords.length; i++) {
String search = searchWords[i];
String replace = replaceWords[i];
if (str.startsWith(search)) {
ret += replace;
str = str.substring(search.length());
break;
}
}
if (i == searchWords.length) {
ret += str.substring(0, 1);
str = str.substring(1);
}
}
return ret;
}
Quelques tests:
System.out.println(replaceEach(
"Once upon a time, there was a foo and a bar.",
new String[]{"foo", "bar"},
new String[]{"bar", "foo"}
));
// Once upon a time, there was a bar and a foo.
System.out.println(replaceEach(
"a p",
new String[]{"a", "p"},
new String[]{"Apple", "pear"}
));
// Apple pear
System.out.println(replaceEach(
"ABCDE",
new String[]{"A", "B", "C", "D", "E"},
new String[]{"B", "C", "E", "E", "F"}
));
// BCEEF
System.out.println(replaceEach(
"ABCDEF",
new String[]{"ABCDEF", "ABC", "DEF"},
new String[]{"XXXXXX", "YYY", "ZZZ"}
));
// XXXXXX
// note the order of search strings, longer strings should be placed first
// in order to make the replacement greedy
Si vous ne souhaitez pas de dépendances, vous pouvez simplement utiliser un tableau permettant uniquement un changement ponctuel. Ce n'est pas la solution la plus efficace, mais cela devrait fonctionner.
public String replace(String sentence, String[]... replace){
String[] words = sentence.split("\\s+");
int[] lock = new int[words.length];
StringBuilder out = new StringBuilder();
for (int i = 0; i < words.length; i++) {
for(String[] r : replace){
if(words[i].contains(r[0]) && lock[i] == 0){
words[i] = words[i].replace(r[0], r[1]);
lock[i] = 1;
}
}
out.append((i < (words.length - 1) ? words[i] + " " : words[i]));
}
return out.toString();
}
Ensuite, cela fonctionnerait.
String story = "Once upon a time, there was a foo and a bar.";
String[] a = {"foo", "bar"};
String[] b = {"bar", "foo"};
String[] c = {"there", "Pocahontas"};
story = replace(story, a, b, c);
System.out.println(story); // Once upon a time, Pocahontas was a bar and a foo.
Eh bien, la réponse la plus courte est ...
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar.";
story = story.replace("foo", "@"+ Word1).replace("bar", Word2).replace("@" + Word2, Word1);
System.out.println(story);
En utilisant la réponse trouvée ici vous pouvez trouver toutes les occurrences des chaînes que vous souhaitez remplacer.
Ainsi, par exemple, vous exécutez le code dans la réponse ci-dessus SO answer. Créez deux tables d'index (disons que bar et foo n'apparaissent pas une fois dans votre chaîne) et vous pouvez utiliser ces tables sur les remplacer dans votre chaîne.
Maintenant, pour remplacer sur des emplacements d'index spécifiques, vous pouvez utiliser:
public static String replaceStringAt(String s, int pos, String c) {
return s.substring(0,pos) + c + s.substring(pos+1);
}
Alors que pos
est l’index de départ de vos chaînes (à partir des tables d’indexes citées plus haut). Supposons donc que vous ayez créé deux tables d’index pour chacune d’elles. Appelons-les indexBar
et indexFoo
.
Maintenant, en les remplaçant, vous pouvez simplement exécuter deux boucles, une pour chaque remplacement que vous souhaitez effectuer.
for(int i=0;i<indexBar.Count();i++)
replaceStringAt(originalString,indexBar[i],newString);
De même une autre boucle pour indexFoo
.
Cela n’est peut-être pas aussi efficace que d’autres réponses ici, mais c’est plus simple à comprendre que Google Maps ou autre.
Cela vous donnerait toujours le résultat que vous souhaitez et pour plusieurs occurrences possibles de chaque chaîne. Tant que vous stockez l'index de chaque occurrence.
De plus, cette réponse ne nécessite aucune récursivité ni aucune dépendance externe. En ce qui concerne la complexité, il s'agit probablement de O (n carré), alors que n est la somme des occurrences des deux mots.
Vous pouvez toujours le remplacer par un mot dont vous êtes sûr qu'il n'apparaîtra nulle part ailleurs dans la chaîne, puis remplacez le deuxième plus tard:
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
story = story.replace("foo", "StringYouAreSureWillNeverOccur").replace("bar", "Word2").replace("StringYouAreSureWillNeverOccur", "Word1");
Notez que cela ne fonctionnera pas correctement si "StringYouAreSureWillNeverOccur"
se produit.
String Word1 = "bar";
String Word2 = "foo";
String story = "Once upon a time, there was a foo and a bar."
Peu astucieux, mais vous devez faire quelques vérifications supplémentaires.
1.convertir la chaîne en tableau de caractères
String temp[] = story.split(" ");//assume there is only spaces.
2. boucle sur temp et remplacez foo
par bar
et bar
par foo
car il n'y a aucune chance d'obtenir une chaîne remplaçable à nouveau.
Pensez à utiliser StringBuilder
Puis stockez l'index où chaque chaîne doit commencer. Si vous utilisez un caractère de lieu réservé à chaque position, supprimez-le et insérez la chaîne d'utilisateurs. Vous pouvez ensuite mapper la position de fin en ajoutant la longueur de la chaîne à la position de départ.
String firstString = "???";
String secondString = "???"
StringBuilder story = new StringBuilder("One upon a time, there was a "
+ firstString
+ " and a "
+ secondString);
int firstWord = 30;
int secondWord = firstWord + firstString.length() + 7;
story.replace(firstWord, firstWord + firstString.length(), userStringOne);
story.replace(secondWord, secondWord + secondString.length(), userStringTwo);
firstString = userStringOne;
secondString = userStringTwo;
return story;
Voici ma version, qui est basée sur Word:
class TextReplace
{
public static void replaceAll (String text, String [] lookup,
String [] replacement, String delimiter)
{
String [] words = text.split(delimiter);
for (int i = 0; i < words.length; i++)
{
int j = find(lookup, words[i]);
if (j >= 0) words[i] = replacement[j];
}
text = StringUtils.join(words, delimiter);
}
public static int find (String [] array, String key)
{
for (int i = 0; i < array.length; i++)
if (array[i].equals(key))
return i;
return (-1);
}
}
Ce que je ne peux que partager, c'est ma propre méthode.
Vous pouvez utiliser un String temp = "<?>";
Ou String.Format();
temporaire
Ceci est mon exemple de code créé dans une application console via c # "Idée seule, pas de réponse exacte".
static void Main(string[] args)
{
String[] Word1 = {"foo", "Once"};
String[] Word2 = {"bar", "time"};
String story = "Once upon a time, there was a foo and a bar.";
story = Switcher(story,Word1,Word2);
Console.WriteLine(story);
Console.Read();
}
// Using a temporary string.
static string Switcher(string text, string[] target, string[] value)
{
string temp = "<?>";
if (target.Length == value.Length)
{
for (int i = 0; i < target.Length; i++)
{
text = text.Replace(target[i], temp);
text = text.Replace(value[i], target[i]);
text = text.Replace(temp, value[i]);
}
}
return text;
}
Ou vous pouvez aussi utiliser la String.Format();
static string Switcher(string text, string[] target, string[] value)
{
if (target.Length == value.Length)
{
for (int i = 0; i < target.Length; i++)
{
text = text.Replace(target[i], "{0}").Replace(value[i], "{1}");
text = String.Format(text, value[i], target[i]);
}
}
return text;
}
Sortie: time upon a Once, there was a bar and a foo.