Java Regex Capturer Des Groupes
J'essaie de comprendre ce bloc de code. Dans la première, qu'est-ce que nous recherchons dans l'expression?
Ma compréhension est que c'est n'importe quel caractère (0 fois ou plus *), suivi par un chiffre entre 0 et 9 (une ou plusieurs fois +), suivie par n'importe quel caractère (0 fois ou plus *).
Lorsque ceci est exécuté, le résultat est:
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0
Quelqu'un pourrait-il traverser ça avec moi?
Quel est l'avantage d'utiliser des groupes de capture?
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTut3 {
public static void main(String args[]) {
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\d+)(.*)";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
// Now create matcher object.
Matcher m = r.matcher(line);
if (m.find()) {
System.out.println("Found value: " + m.group(0));
System.out.println("Found value: " + m.group(1));
System.out.println("Found value: " + m.group(2));
} else {
System.out.println("NO MATCH");
}
}
}
4 réponses
Le problème que vous rencontrez est le type de quantificateur. Vous utilisez un quantificateur greedy dans votre premier groupe (index 1 - l'index 0 représente l'ensemble Pattern
), ce qui signifie qu'il correspondra autant qu'il le peut (et comme il s'agit de n'importe quel caractère , il correspondra à autant de caractères {[9] } afin de remplir la condition pour les groupes suivants).
En bref, votre 1er groupe .*
correspond à rien, tant que le groupe suivant \\d+
peut correspondre à quelque chose (en ce cas, le dernier chiffre).
Selon le 3ème groupe, il correspondra à n'importe quoi après le dernier chiffre.
Si vous le changer pour un réticents quantificateur dans votre 1er groupe, vous obtiendrez le résultat je suppose que vous attendez, c'est la 3000 partie.
Notez l' point d'interrogation dans le 1er groupe.
String line = "This order was placed for QT3000! OK?";
Pattern pattern = Pattern.compile("(.*?)(\\d+)(.*)");
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
System.out.println("group 1: " + matcher.group(1));
System.out.println("group 2: " + matcher.group(2));
System.out.println("group 3: " + matcher.group(3));
}
Sortie:
group 1: This order was placed for QT
group 2: 3000
group 3: ! OK?
Plus d'infos sur Java Pattern
ici.
Enfin, les groupes de capture sont délimités par arrondir les crochets, et fournir un moyen très utile d'utiliser des références arrières (entre autres), une fois que votre Pattern
est adapté à l'entrée.
En Java, les groupes 6 ne peuvent être référencés que par leur ordre (attention aux groupes imbriqués et à la subtilité de l'ordre).
Dans Java 7, c'est beaucoup plus facile, car vous pouvez utiliser des groupes nommés.
C'est totalement OK.
- le premier groupe (
m.group(0)
) capture toujours Toute la zone couverte par votre expression régulière. Dans ce cas, c'est l'ensemble de la chaîne. - Les expressions régulières sont gourmandes par défaut, ce qui signifie que le premier groupe capture autant que possible sans violer l'expression rationnelle. Le
(.*)(\\d+)
(la première partie de votre regex) couvre la...QT300
int le premier groupe et le0
dans le second. - Vous pouvez rapidement résoudre ce problème en faisant le premier groupe non gourmand: changez
(.*)
en(.*?)
.
Pour plus d'informations sur greedy vs. lazy, consultez ce site.
Votre compréhension est correcte. Cependant, si nous marchons à travers:
- {[0] } va avaler toute la chaîne;
- il devra rendre des caractères pour que
(\\d+)
soit satisfait (c'est pourquoi0
est capturé, et non3000
); - le dernier {[0] } capturera alors le reste.
Je ne suis pas sûr de ce que l'intention initiale de l'auteur était, cependant.
De la doc:
Capturing groups</a> are indexed from left
* to right, starting at one. Group zero denotes the entire pattern, so
* the expression m.group(0) is equivalent to m.group().
Donc capturer le groupe 0 envoyer toute la ligne.