Puis-je remplacer des groupes dans regex Java?

J’ai ce code et je veux savoir si je ne peux remplacer que des groupes (pas tous les motifs) dans regex Java. Code:

//... Pattern p = Pattern.comstack("(\\d).*(\\d)"); Ssortingng input = "6 example input 4"; Matcher m = p.matcher(input); if (m.find()) { //Now I want replace group one ( (\\d) ) with number //and group two (too (\\d) ) with 1, but I don't know how. } 

Utilisez $n (où n est un chiffre) pour faire référence aux sous- replaceFirst(...) capturées dans replaceFirst(...) . Je suppose que vous vouliez remplacer le premier groupe par la chaîne littérale “nombre” et le deuxième groupe par la valeur du premier groupe.

 Pattern p = Pattern.comstack("(\\d)(.*)(\\d)"); Ssortingng input = "6 example input 4"; Matcher m = p.matcher(input); if (m.find()) { // replace first number with "number" and second number with the first Ssortingng output = m.replaceFirst("number $3$1"); // number 46 } 

Considérez (\D+) pour le deuxième groupe au lieu de (.*) . * est un masortingçage gourmand et consum d’abord le dernier chiffre. Le matcher devra alors revenir en arrière lorsqu’il réalisera que la finale (\d) n’a rien à faire avant de pouvoir correspondre au chiffre final.

Vous pouvez utiliser Matcher#start(group) et Matcher#end(group) pour créer une méthode de remplacement générique:

 public static Ssortingng replaceGroup(Ssortingng regex, Ssortingng source, int groupToReplace, Ssortingng replacement) { return replaceGroup(regex, source, groupToReplace, 1, replacement); } public static Ssortingng replaceGroup(Ssortingng regex, Ssortingng source, int groupToReplace, int groupOccurrence, Ssortingng replacement) { Matcher m = Pattern.comstack(regex).matcher(source); for (int i = 0; i < groupOccurrence; i++) if (!m.find()) return source; // pattern not met, may also throw an exception here return new StringBuilder(source).replace(m.start(groupToReplace), m.end(groupToReplace), replacement).toString(); } public static void main(String[] args) { // replace with "%" what was matched by group 1 // input: aaa123ccc // output: %123ccc System.out.println(replaceGroup("([az]+)([0-9]+)([az]+)", "aaa123ccc", 1, "%")); // replace with "!!!" what was matched the 4th time by the group 2 // input: a1b2c3d4e5 // output: a1b2c3d!!!e5 System.out.println(replaceGroup("([az])(\\d)", "a1b2c3d4e5", 2, 4, "!!!")); } 

Vérifiez la démo en ligne ici .

Ajoutez un troisième groupe en ajoutant parens autour de .* , Puis remplacez la sous-séquence par "number" + m.group(2) + "1" . par exemple:

 Ssortingng output = m.replaceFirst("number" + m.group(2) + "1"); 

Désolé de battre un cheval mort, mais c’est assez étrange que personne ne le fasse remarquer – “Oui, c’est possible, mais c’est le contraire de la façon dont vous utilisez les groupes de capture dans la vraie vie”.

Si vous utilisez Regex comme il se doit, la solution est aussi simple que cela:

 "6 example input 4".replaceAll("(?:\\d)(.*)(?:\\d)", "number$11"); 

Ou comme le souligne justement shmosel ci-dessous,

 "6 example input 4".replaceAll("\d(.*)\d", "number$11"); 

… puisque dans votre regex il n’y a pas de bonne raison de regrouper les décimales.

Vous n’utilisez généralement pas de groupes de capture sur les parties de la chaîne que vous souhaitez supprimer , vous les utilisez sur la partie de la chaîne que vous souhaitez conserver .

Si vous voulez vraiment que les groupes que vous voulez remplacer, ce que vous voulez probablement, c’est un moteur de template (par exemple, moustache, ejs, SsortingngTemplate, …).


Pour les curieux, même les groupes non capturés dans les expressions rationnelles ne sont là que pour le cas où le moteur regex en aurait besoin pour reconnaître et ignorer le texte variable. Par exemple, dans

 (?:abc)*(capture me)(?:bcd)* 

vous en avez besoin si votre entrée peut ressembler à “abcabc capture me bcdbcd” ou “abc capture me bcd” ou même simplement “capture-moi”.

Ou pour le dire autrement: si le texte est toujours le même et que vous ne le capturez pas, il n’y a aucune raison d’utiliser des groupes.

Vous pouvez utiliser les méthodes matcher.start () et matcher.end () pour obtenir les positions du groupe. Donc, en utilisant ces positions, vous pouvez facilement remplacer n’importe quel texte.

Voici une solution différente, qui permet également de remplacer un seul groupe dans plusieurs correspondances. Il utilise des stacks pour inverser l’ordre d’exécution, de sorte que l’opération de chaîne peut être exécutée en toute sécurité.

 private static void demo () { final Ssortingng sourceSsortingng = "hello world!"; final Ssortingng regex = "(hello) (world)(!)"; final Pattern pattern = Pattern.comstack(regex); Ssortingng result = replaceTextOfMatchGroup(sourceSsortingng, pattern, 2, world -> world.toUpperCase()); System.out.println(result); // output: hello WORLD! } public static Ssortingng replaceTextOfMatchGroup(Ssortingng sourceSsortingng, Pattern pattern, int groupToReplace, Function replaceStrategy) { Stack startPositions = new Stack<>(); Stack endPositions = new Stack<>(); Matcher matcher = pattern.matcher(sourceString); while (matcher.find()) { startPositions.push(matcher.start(groupToReplace)); endPositions.push(matcher.end(groupToReplace)); } StringBuilder sb = new StringBuilder(sourceString); while (! startPositions.isEmpty()) { int start = startPositions.pop(); int end = endPositions.pop(); if (start >= 0 && end >= 0) { sb.replace(start, end, replaceStrategy.apply(sourceSsortingng.subssortingng(start, end))); } } return sb.toSsortingng(); }