Java regex capture des index de groupes

113

J'ai la ligne suivante,

typeName="ABC:xxxxx;";

Je dois aller chercher le mot ABC,

J'ai écrit l'extrait de code suivant,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Alors si je mets group(0)j'obtiens ABC:mais si je mets group(1)ça l'est ABC, alors je veux savoir

  1. Qu'est-ce que cela 0et que 1signifie? Ce sera mieux si quelqu'un peut m'expliquer avec de bons exemples.

  2. Le modèle regex contient un :, alors pourquoi le group(1)résultat omet cela? Le groupe 1 détecte-t-il tous les mots entre parenthèses?

  3. Donc, si je mets deux autres parenthèses telles que \\s*(\d*)(.*),: alors, y aura-t-il deux groupes? group(1)va retourner la (\d*)pièce et group(2)retourner la (.*)pièce?

L'extrait de code a été donné dans le but de dissiper mes confusions. Ce n'est pas le code dont je parle. Le code donné ci-dessus peut être fait d' String.split()une manière beaucoup plus simple.

P basak
la source

Réponses:

182

Capture et regroupement

Le groupe de capture (pattern) crée un groupe qui possède une propriété de capture .

Un autre associé que vous pourriez souvent voir (et utiliser) est (?:pattern), qui crée un groupe sans capturer de propriété, donc nommé non capturant .

Un groupe est généralement utilisé lorsque vous devez répéter une séquence de motifs, par exemple (\.\w+)+ , ou pour spécifier où l'alternance doit prendre effet, par exemple ^(0*1|1*0)$( ^, alors 0*1ou 1*0, alors $) versus ^0*1|1*0$( ^0*1ou1*0$ ).

Un groupe de capture, en dehors du regroupement, enregistrera également le texte correspondant au motif à l'intérieur du groupe de capture (pattern) . En utilisant votre exemple, (.*):, .*matchs ABCet :matchs :, et depuis .*est à l' intérieur groupe capture (.*), le texte ABCest enregistré pour le groupe de capture 1.

Numéro de groupe

Le motif entier est défini comme étant le groupe numéro 0.

Tout groupe de capture dans le modèle commence l'indexation à partir de 1. Les indices sont définis par l'ordre de parenthèses ouvrantes des groupes de capture . À titre d'exemple, voici les 5 groupes de capture dans le modèle ci-dessous:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Les numéros de groupe sont utilisés en référence arrière \ndans le modèle et $ndans la chaîne de remplacement.

Dans d'autres saveurs de regex (PCRE, Perl), ils peuvent également être utilisés dans les appels de sous-routine .

Vous pouvez accéder au texte correspondant à certains groupes avec Matcher.group(int group) . Les numéros de groupe peuvent être identifiés avec la règle indiquée ci-dessus.

Dans certaines versions de regex (PCRE, Perl), il existe une fonction de réinitialisation de branche qui vous permet d'utiliser le même numéro pour capturer des groupes dans différentes branches d'alternance .

Nom de groupe

À partir de Java 7, vous pouvez définir un groupe de capture nommé (?<name>pattern) et accéder au contenu correspondant àMatcher.group(String name) . L'expression régulière est plus longue, mais le code est plus significatif, car il indique ce que vous essayez de faire correspondre ou d'extraire avec l'expression régulière.

Les noms de groupe sont utilisés en back-reference \k<name> dans le pattern et${name} dans la chaîne de remplacement.

Les groupes de capture nommés sont toujours numérotés avec le même schéma de numérotation, de sorte qu'ils sont également accessibles via Matcher.group(int group) .

En interne, l'implémentation de Java correspond simplement du nom au numéro de groupe. Par conséquent, vous ne pouvez pas utiliser le même nom pour 2 groupes de capture différents.

nhahtdh
la source
1
HOU LA LA! Merci @nhahtdh d'avoir expliqué aux groupes sans capture comment fonctionne l'ordre des groupes d'imbrication. J'étais perplexe sur la façon dont les numéros de groupe fonctionnaient jusqu'à ce que je lis enfin votre explication. Merci beaucoup!
MMeah
92

Pour le reste d'entre nous

Voici un exemple simple et clair de la façon dont cela fonctionne

Regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

Chaîne: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Comme vous pouvez le voir, j'ai créé CINQ groupes qui sont chacun entre parenthèses.

J'ai inclus les! * Et *! de chaque côté pour le rendre plus clair. Notez qu'aucun de ces caractères n'est dans le RegEx et ne sera donc pas produit dans les résultats. Group (0) vous donne simplement la chaîne entière correspondante (tous mes critères de recherche sur une seule ligne). Le groupe 1 s'arrête juste avant le premier espace car le caractère espace n'a pas été inclus dans les critères de recherche. Les groupes 2 et 4 sont simplement l'espace blanc, qui dans ce cas est littéralement un caractère d'espace, mais pourrait aussi être une tabulation ou un saut de ligne etc. Le groupe 3 inclut l'espace parce que je l'ai mis dans les critères de recherche ... etc.

J'espère que cela a du sens.

Michael Sims
la source
1
exemple parfait et facile à comprendre pour les débutants. J'ai un doute est-ce la même chose que le regroupement reg ex en python? ou bien y a-t-il une différence? Je suis nouveau dans reg ex c'est pourquoi je suis un peu confus dans les deux langues.
Mani
1
Ce n'est pas une expression régulière Java valide: les barres obliques inverses doivent être doublées.
Nicolas Raoul
1
@NicolasRaoul: La double barre oblique inverse est due à la syntaxe d'échappement dans la chaîne littérale. La syntaxe réelle de l'expression régulière (c'est-à-dire si vous imprimez la chaîne contenant l'expression régulière sur la console) ne nécessite pas de double barre oblique inverse.
nhahtdh
@NicolasRaoul Si vous deviez copier et coller ma chaîne d'expression régulière dans le code java réel en utilisant un IDE compétent, l'EDI formaterait correctement les barres obliques d'échappement selon les besoins. Mais mon Regex est techniquement et syntaxiquement correct et il sert l'objectif principal qui est de démontrer l'association entre le code regex et les résultats obtenus (en utilisant un exemple très spécifique) ... alléger un peu ... ☺
Michael Sims
44

Les parenthèses ()sont utilisées pour permettre le regroupement de phrases regex.

Le group(1)contient la chaîne entre parenthèses (.*)donc .*dans ce cas

Et group(0)contient toute la chaîne correspondante.

Si vous aviez plus de groupes (lecture (...)), ils seraient mis en groupes avec les prochains index (2, 3 et ainsi de suite).

Michal Borek
la source
2
Donc, j'ai raison de dire que l'ajout de parenthèses sert en fait à créer des groupes?
P basak
3
Oui, on peut dire ça.
Michal Borek