J'ai le problème suivant qui déclare
Remplacez tous les caractères d'une chaîne par
+
symbole sauf les instances de la chaîne donnée dans la méthode
par exemple, si la chaîne donnée était abc123efg
et ils veulent que je remplace chaque caractère sauf chaque occurrence de 123
alors il deviendrait +++123+++
.
J'ai pensé qu'une expression régulière est probablement la meilleure pour cela et j'ai trouvé cela.
str.replaceAll("[^str]","+")
où str est une variable, mais cela ne me permet pas d'utiliser la méthode sans la mettre entre guillemets. Si je veux juste remplacer la chaîne de variable str, comment faire? Je l'ai exécuté avec la chaîne tapée manuellement et cela a fonctionné sur la méthode, mais puis-je simplement entrer une variable?
en ce moment je crois que sa recherche de la chaîne "str" et non de la chaîne variable.
Voici la sortie de son droit pour de nombreux cas, sauf pour deux :(
Liste des cas de test ouverts:
plusOut("12xy34", "xy") → "++xy++"
plusOut("12xy34", "1") → "1+++++"
plusOut("12xy34xyabcxy", "xy") → "++xy++xy+++xy"
plusOut("abXYabcXYZ", "ab") → "ab++ab++++"
plusOut("abXYabcXYZ", "abc") → "++++abc+++"
plusOut("abXYabcXYZ", "XY") → "++XY+++XY+"
plusOut("abXYxyzXYZ", "XYZ") → "+++++++XYZ"
plusOut("--++ab", "++") → "++++++"
plusOut("aaxxxxbb", "xx") → "++xxxx++"
plusOut("123123", "3") → "++3++3"
Il semble que ce soit le problème de plusOut
sur CodingBat.
J'ai eu 3 solutions à ce problème et j'ai écrit une nouvelle solution de streaming juste pour le plaisir.
Créez un StringBuilder à partir de la chaîne d'entrée et recherchez le mot à chaque position. Remplacez le caractère s'il ne correspond pas et ignorez la longueur du mot s'il est trouvé.
public String plusOut(String str, String Word) {
StringBuilder out = new StringBuilder(str);
for (int i = 0; i < out.length(); ) {
if (!str.startsWith(Word, i))
out.setCharAt(i++, '+');
else
i += Word.length();
}
return out.toString();
}
C'est probablement la réponse attendue pour un programmeur débutant, bien que l'on suppose que la chaîne ne contient aucun caractère de plan astral, qui serait représenté par 2 caractères au lieu de 1.
public String plusOut(String str, String Word) {
return str.replaceAll(Java.util.regex.Pattern.quote(Word), "@").replaceAll("[^@]", "+").replaceAll("@", Word);
}
Pas une bonne solution car elle suppose qu'un certain caractère ou séquence de caractères n'apparaît pas dans la chaîne.
Notez l'utilisation de Pattern.quote
Pour éviter que le Word
soit interprété comme syntaxe regex par la méthode replaceAll
.
\G
public String plusOut(String str, String Word) {
Word = Java.util.regex.Pattern.quote(Word);
return str.replaceAll("\\G((?:" + Word + ")*+).", "$1+");
}
Construisez regex \G((?:Word)*+).
, qui fait plus ou moins ce que fait la solution 1:
\G
S'assure que le match commence là où le match précédent s'est arrêté((?:Word)*+)
Sélectionne 0 ou plusieurs instances de Word
- le cas échéant, afin que nous puissions les conserver dans le remplacement avec $1
. La clé ici est le quantificateur possessif *+
, Qui force l'expression régulière à conserver n'importe quelle instance du Word
qu'il trouve. Sinon, l'expression régulière ne fonctionnera pas correctement lorsque le Word
apparaîtra à la fin de la chaîne, car les expressions régulières reviennent sur .
.
Ne fera partie d'aucun Word
, car la partie précédente récupère déjà toutes les apparitions consécutives de Word
et interdit la marche arrière. Nous allons remplacer cela par +
public String plusOut(String str, String Word) {
return String.join(Word,
Arrays.stream(str.split(Java.util.regex.Pattern.quote(Word), -1))
.map((String s) -> s.replaceAll("(?s:.)", "+"))
.collect(Collectors.toList()));
}
L'idée est de diviser la chaîne par Word
, de faire le remplacement sur le reste et de les joindre à nouveau avec Word
en utilisant la méthode String.join
.
Pattern.quote
Pour éviter que split
interprète le Word
comme une expression régulière. Puisque split
supprime par défaut la chaîne vide à la fin du tableau, nous devons utiliser -1
Dans le deuxième paramètre pour que split
laisse ces chaînes vides seules.+
. Dans Java 11, nous pouvons utiliser s -> String.repeat(s.length())
à la place.C'est un peu plus compliqué que vous ne le pensez au départ car vous n'avez pas seulement besoin de faire correspondre caractères , mais le absence de phrase spécifique - un jeu de caractères nié ne suffit pas. Si la chaîne est 123, vous aurez besoin de:
(?<=^|123)(?!123).*?(?=123|$)
https://regex101.com/r/EZWMqM/1/
Autrement dit, recherchez le début de la chaîne ou "123", assurez-vous que la position actuelle n'est pas suivie de 123, puis répétez paresseusement n'importe quel caractère jusqu'à ce que la recherche de correspondance corresponde à "123" ou à la fin de la chaîne. Cela correspondra à tous les caractères qui ne sont pas dans une sous-chaîne "123". Ensuite, vous devez remplacer chaque caractère par un +
, après quoi vous pouvez utiliser appendReplacement
et un StringBuffer
pour créer la chaîne de résultat:
String inputPhrase = "123";
String inputStr = "abc123efg123123hij";
StringBuffer resultString = new StringBuffer();
Pattern regex = Pattern.compile("(?<=^|" + inputPhrase + ")(?!" + inputPhrase + ").*?(?=" + inputPhrase + "|$)");
Matcher m = regex.matcher(inputStr);
while (m.find()) {
String replacement = m.group(0).replaceAll(".", "+");
m.appendReplacement(resultString, replacement);
}
m.appendTail(resultString);
System.out.println(resultString.toString());
Production:
+++123+++123123+++
Notez que si le inputPhrase
peut contenir un caractère avec une signification spéciale dans une expression régulière, vous devrez d'abord les échapper avant de concaténer dans le motif.
Vous pouvez le faire en une seule ligne:
input = input.replaceAll("((?:" + str + ")+)?(?!" + str + ").((?:" + str + ")+)?", "$1+$2");
Cela capture facultativement "123" de chaque côté de chaque caractère et les remet en place (un blanc s'il n'y a pas de "123"):
Pour que cela fonctionne, vous avez besoin d'une bête d'un modèle. Supposons que vous utilisiez le cas de test suivant à titre d'exemple:
plusOut("abXYxyzXYZ", "XYZ") → "+++++++XYZ"
Ce que vous devez faire est de créer une série de clauses dans votre modèle pour correspondre à un seul caractère à la fois:
[^XYZ]
X(?!YZ)
(?<!X)Y
Y(?!Z)
(?<!XY)Z
Un exemple de ce remplacement peut être trouvé ici: https://regex101.com/r/jK5wU3/4
Voici un exemple de la façon dont cela pourrait fonctionner (certainement pas optimisé, mais cela fonctionne):
import Java.util.regex.Pattern;
public class Test {
public static void plusOut(String text, String exclude) {
StringBuilder pattern = new StringBuilder("");
for (int i=0; i<exclude.length(); i++) {
Character target = exclude.charAt(i);
String prefix = (i > 0) ? exclude.substring(0, i) : "";
String postfix = (i < exclude.length() - 1) ? exclude.substring(i+1) : "";
// add the look-behind (?<!X)Y
if (!prefix.isEmpty()) {
pattern.append("(?<!").append(Pattern.quote(prefix)).append(")")
.append(Pattern.quote(target.toString())).append("|");
}
// add the look-ahead X(?!YZ)
if (!postfix.isEmpty()) {
pattern.append(Pattern.quote(target.toString()))
.append("(?!").append(Pattern.quote(postfix)).append(")|");
}
}
// add in the other character exclusion
pattern.append("[^" + Pattern.quote(exclude) + "]");
System.out.println(text.replaceAll(pattern.toString(), "+"));
}
public static void main(String [] args) {
plusOut("12xy34", "xy");
plusOut("12xy34", "1");
plusOut("12xy34xyabcxy", "xy");
plusOut("abXYabcXYZ", "ab");
plusOut("abXYabcXYZ", "abc");
plusOut("abXYabcXYZ", "XY");
plusOut("abXYxyzXYZ", "XYZ");
plusOut("--++ab", "++");
plusOut("aaxxxxbb", "xx");
plusOut("123123", "3");
}
}
MISE À JOUR: Même cela ne fonctionne pas tout à fait car il ne peut pas gérer les exclusions qui ne sont que des caractères répétés, comme "xx". Les expressions régulières ne sont certainement pas le bon outil pour cela, mais j'ai pensé que cela pourrait être possible. Après avoir fouillé, je ne suis pas sûr qu'un modèle existe même qui pourrait faire fonctionner cela.
Le problème dans votre solution que vous mettez un ensemble de chaîne d'instance str.replaceAll("[^str]","+")
qui exclura tout caractère de la variable str
et qui ne résoudra pas votre problème
[~ # ~] ex [~ # ~] : lorsque vous essayez str.replaceAll("[^XYZ]","+")
il exclura toute combinaison de caractères X
, caractère Y
et caractère Z
de votre méthode de remplacement pour obtenir "++XY+++XYZ
".
En fait, vous devez exclure une séquence de caractères à la place dans str.replaceAll
.
Vous pouvez le faire en utilisant un groupe de capture de caractères comme (XYZ)
Puis utilisez un lookahead négatif pour faire correspondre une chaîne qui ne contient pas de séquence de caractères: ^((?!XYZ).)*$
Vérifiez ceci solution pour plus d'informations sur ce problème, mais vous devez savoir qu'il peut être compliqué de trouver une expression régulière pour le faire directement.
J'ai trouvé deux solutions simples à ce problème:
Solution 1 :
Vous pouvez implémenter une méthode pour remplacer tous les caractères par '+
' À l'exception de l'instance de la chaîne donnée:
String exWord = "XYZ";
String str = "abXYxyzXYZ";
for(int i = 0; i < str.length(); i++){
// exclude any instance string of exWord from replacing process in str
if(str.substring(i, str.length()).indexOf(exWord) + i == i){
i = i + exWord.length()-1;
}
else{
str = str.substring(0,i) + "+" + str.substring(i+1);//replace each character with '+' symbol
}
}
Remarque : str.substring(i, str.length()).indexOf(exWord) + i
cette instruction if exclura toute chaîne d'instance de exWord
du remplacement du processus dans str
.
Sortie :
+++++++XYZ
Solution 2 :
Vous pouvez essayer cette approche en utilisant la méthode ReplaceAll et elle ne nécessite aucune expression régulière complexe:
String exWord = "XYZ";
String str = "abXYxyzXYZ";
str = str.replaceAll(exWord,"*"); // replace instance string with * symbol
str = str.replaceAll("[^*]","+"); // replace all characters with + symbol except *
str = str.replaceAll("\\*",exWord); // replace * symbol with instance string
Remarque : Cette solution ne fonctionnera que si votre chaîne d'entrée str
ne contient aucun symbole *
.
Vous devez également échapper tout caractère ayant une signification spéciale dans une expression régulière dans la chaîne d'instance de phrase exWord
comme: exWord = "++"
.
Absolument juste pour le plaisir, une solution utilisant CharBuffer
(de manière inattendue, il en a fallu beaucoup plus que ce que j'espérais initialement):
private static String plusOutCharBuffer(String input, String match) {
int size = match.length();
CharBuffer cb = CharBuffer.wrap(input.toCharArray());
CharBuffer Word = CharBuffer.wrap(match);
int x = 0;
for (; cb.remaining() > 0;) {
if (!cb.subSequence(0, size < cb.remaining() ? size : cb.remaining()).equals(Word)) {
cb.put(x, '+');
cb.clear().position(++x);
} else {
cb.clear().position(x = x + size);
}
}
return cb.clear().toString();
}
Donc, au lieu de trouver une expression régulière qui correspond à l'absence de chaîne. Nous pourrions tout aussi bien faire correspondre la phrase sélectionnée et ajouter +
le nombre de caractères ignorés.
StringBuilder sb = new StringBuilder();
Matcher m = Pattern.compile(Pattern.quote(str)).matcher(input);
while (m.find()) {
for (int i = 0; i < m.start(); i++) sb.append('+');
sb.append(str);
}
int remaining = input.length() - sb.length();
for (int i = 0; i < remaining; i++) {
sb.append('+');
}