web-dev-qa-db-fra.com

Java Regex Capturing Groups

J'essaie de comprendre ce bloc de code. Dans le premier, que recherchons-nous dans l'expression?

D'après ce que je comprends, il s'agit de n'importe quel caractère (0 fois ou plus *) suivi d'un nombre compris entre 0 et 9 (une ou plusieurs fois +), suivi d'un caractère quelconque (0 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 s'il vous plaît passer par là 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");
        }
    }

}
155
Xivilai

Le problème que vous rencontrez concerne le type de quantificateur. Vous utilisez un quantificateur glouton dans votre premier groupe (index 1 - L'indice 0 représente l'ensemble Pattern), ce qui signifie qu'il correspondra autant que possible (et comme il s'agit de n'importe quel caractère , il correspondra autant de caractères qu'il y en a pour remplir la condition des groupes suivants).

En bref, votre premier groupe .* correspond à quoi que ce soit tant que le groupe suivant \\d+ peut correspondre à quelque chose (dans ce cas, le dernier chiffre).

Selon le troisième groupe, il correspondra à tout ce qui se trouve après le dernier chiffre.

Si vous le changez en un quantificateur réticent de votre 1er groupe, vous obtiendrez le résultat que vous attendez, à savoir le 3000 partie.

Notez le 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'informations sur Java Patternici .

Enfin, les groupes de capture sont délimités par des crochets et constituent un moyen très utile d’utiliser des références arrière (entre autres), une fois que votre Pattern correspond à l’entrée.

Dans Java 6, les groupes 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.

221
Mena

C'est totalement OK.

  1. Le premier groupe (m.group(0)) capture toujours la totalité de la zone couverte par votre expression régulière . Dans ce cas, c'est toute la chaîne.
  2. Les expressions régulières sont gourmandes par défaut, ce qui signifie que le premier groupe capture autant que possible sans violer les expressions rationnelles. Le (.*)(\\d+) (la première partie de votre regex) couvre le ...QT300 int du premier groupe et le 0 du second.
  3. Vous pouvez rapidement résoudre ce problème en rendant le premier groupe non gourmand: changez (.*) en (.*?).

Pour plus d'informations sur les gourmands vs les paresseux, vérifiez ce site.

15
f1sh

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, le groupe de capture 0 envoie toute la ligne.

4
Michael Laffargue

Votre compréhension est correcte. Cependant, si nous traversons:

  • (.*) avalera toute la chaîne;
  • il faudra redonner des caractères pour que (\\d+) soit satistifed (c'est pourquoi 0 est capturé et non 3000);
  • le dernier (.*) capturera le reste.

Je ne suis toutefois pas certain de l'intention initiale de l'auteur.

3
fge