Question Qu'est-ce qu'un groupe non-capturant? Que fait (? :) faire?


Comment ?: est utilisé et à quoi ça sert?


1320
2017-08-18 13:17


origine


Réponses:


Laissez-moi essayer d'expliquer ceci avec un exemple.

Considérez le texte suivant:

https://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex

Maintenant, si j'applique l'expression rationnelle ci-dessous ...

(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

... j'obtiendrais le résultat suivant:

Match "https://stackoverflow.com/"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/questions/tagged/regex"

Mais je ne me soucie pas du protocole - je veux juste l'hôte et le chemin de l'URL. Donc, je change la regex pour inclure le groupe non-capturant (?:).

(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

Maintenant, mon résultat ressemble à ceci:

Match "https://stackoverflow.com/"
     Group 1: "stackoverflow.com"
     Group 2: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "stackoverflow.com"
     Group 2: "/questions/tagged/regex"

Voir? Le premier groupe n'a pas été capturé. L'analyseur l'utilise pour faire correspondre le texte, mais l'ignore plus tard, dans le résultat final.


MODIFIER:

Comme demandé, permettez-moi d'essayer d'expliquer les groupes aussi.

Eh bien, les groupes servent à plusieurs fins. Ils peuvent vous aider à extraire des informations exactes d'une correspondance plus grande (qui peut également être nommée), ils vous permettent de ré-apparier un groupe correspondant précédent, et peuvent être utilisés pour des substitutions. Essayons quelques exemples, allons-nous?

Ok, imaginez que vous avez une sorte de XML ou de HTML (sachez que regex peut ne pas être le meilleur outil pour le travail, mais c'est sympa comme exemple). Vous voulez analyser les tags, vous pouvez donc faire quelque chose comme ça (j'ai ajouté des espaces pour le rendre plus facile à comprendre):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
   \<(.+?)\> [^<]*? \</\1\>

La première regex a un groupe nommé (TAG), tandis que la seconde utilise un groupe commun. Les deux regex font la même chose: ils utilisent la valeur du premier groupe (le nom de la balise) pour correspondre à la balise de fermeture. La différence est que le premier utilise le nom pour correspondre à la valeur, et le second utilise l'index du groupe (qui commence à 1).

Essayons quelques substitutions maintenant. Considérez le texte suivant:

Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.

Maintenant, utilisons cette regex stupide:

\b(\S)(\S)(\S)(\S*)\b

Cette expression rationnelle correspond à au moins 3 caractères et utilise des groupes pour séparer les trois premières lettres. Le résultat est le suivant:

Match "Lorem"
     Group 1: "L"
     Group 2: "o"
     Group 3: "r"
     Group 4: "em"
Match "ipsum"
     Group 1: "i"
     Group 2: "p"
     Group 3: "s"
     Group 4: "um"
...

Match "consectetuer"
     Group 1: "c"
     Group 2: "o"
     Group 3: "n"
     Group 4: "sectetuer"
...

Donc, si nous appliquons la chaîne de substitution ...

$1_$3$2_$4

... dessus, nous essayons d'utiliser le premier groupe, d'ajouter un trait de soulignement, d'utiliser le troisième groupe, puis le deuxième groupe, d'ajouter un autre trait de soulignement, puis le quatrième groupe. La chaîne résultante serait comme celle ci-dessous.

L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.

Vous pouvez également utiliser des groupes nommés pour les substitutions, en utilisant ${name}.

Pour jouer avec les regex, je recommande http://regex101.com/, qui offre une bonne quantité de détails sur le fonctionnement de la regex; il offre également quelques moteurs regex à choisir.


1828
2017-08-18 15:39



Vous pouvez utiliser des groupes de capture pour organiser et analyser une expression. Un groupe non-capturant a le premier avantage, mais n'a pas la surcharge de la seconde. Vous pouvez toujours dire qu'un groupe non-capturant est facultatif, par exemple.

Supposons que vous vouliez faire correspondre un texte numérique, mais que certains nombres puissent être écrits comme 1er, 2ème, 3ème, 4ème, ... Si vous voulez capturer la partie numérique, mais pas le suffixe (facultatif), vous pouvez utiliser un groupe non-capturant .

([0-9]+)(?:st|nd|rd|th)?

Cela correspondra aux nombres sous la forme 1, 2, 3 ... ou sous la forme 1, 2, 3, ... mais il ne capturera que la partie numérique.


135
2017-08-18 13:24



?: est utilisé lorsque vous voulez grouper une expression, mais vous ne voulez pas l'enregistrer en tant que partie capturée / capturée de la chaîne.

Un exemple pourrait correspondre à une adresse IP:

/(?:\d{1,3}\.){3}\d{1,3}/

Notez que je ne me soucie pas de sauver les 3 premiers octets, mais le (?:...) Le regroupement me permet de raccourcir l'expression régulière sans encourir les frais généraux de capture et de stockage d'un match.


87
2017-08-18 13:22



Cela rend le groupe non-capturant, ce qui signifie que la sous-chaîne correspondant à ce groupe ne sera pas incluse dans la liste des captures. Un exemple en rubis pour illustrer la différence:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]

27
2017-08-18 13:23



MOTIVATION HISTORIQUE: L'existence de groupes non-capturants peut s'expliquer par l'utilisation de parenthèses. Considérons les expressions (a | b) c et a | bc, dues à la priorité de concaténation sur |, ces expressions représentent deux langages différents ({ac, bc} et {a, bc} respectivement). Cependant, les parenthèses sont également utilisées comme groupe correspondant (comme expliqué par les autres réponses ...).

Lorsque vous voulez avoir des parenthèses mais ne pas capturer la sous-expression, vous utilisez des GROUPES NON-CAPTURANTS. Dans l'exemple, (?: A | b) c


13
2018-02-04 08:07



Groupes qui Capturer vous pouvez utiliser plus tard dans la regex pour correspondre OU vous pouvez les utiliser dans la partie de remplacement de l'expression rationnelle. Faire un non-capture groupe exclut simplement que ce groupe soit utilisé pour l'une ou l'autre de ces raisons.

Les groupes qui ne capturent pas sont parfaits si vous essayez de capturer beaucoup de choses différentes et il y a des groupes que vous ne voulez pas capturer.

C'est à peu près la raison pour laquelle ils existent. Pendant que vous apprenez sur les groupes, renseignez-vous sur Groupes atomiques, ils font beaucoup! Il y a aussi des groupes de lookaround mais ils sont un peu plus complexes et pas tellement utilisés.

Exemple d'utilisation ultérieure dans la regex (backreference):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>  [Trouve une balise xml (sans support ns)]

([A-Z][A-Z0-9]*) est un groupe de capture (dans ce cas, c'est la variable)

Plus tard dans la regex est \1 ce qui signifie qu'il ne correspondra qu'au même texte que celui du premier groupe (le ([A-Z][A-Z0-9]*) groupe) (dans ce cas, il correspond à l'étiquette de fin).


12
2017-08-18 13:22



Laissez-moi essayer ceci avec un exemple:

Regex Code: - (?:animal)(?:=)(\w+)(,)\1\2

Chaîne de recherche: -

Ligne 1 - animal = chat, chien, chat, tigre, chien

Ligne 2 - animal = chat, chat, chien, chien, tigre

Ligne 3 - animal = chien, chien, chat, chat, tigre

(?:animal) -> Groupe non capturé 1

(?:=)-> Groupe non capturé 2

(\w+)-> Groupe capturé 1

(,)-> Capturé Groupe 2

\1 -> résultat du groupe capturé 1 i.e Dans la ligne 1 est le chat, Dans la ligne 2 est le chat, Dans la ligne 3 est le chien.

\2 -> résultat du groupe capturé 2 i.e virgule (,)

Donc, dans ce code en donnant \ 1 et \ 2, nous rappelons ou répétons le résultat du groupe capturé 1 et 2 respectivement plus tard dans le code.

Selon l'ordre du code (?: Animal) devrait être le groupe 1 et (?: =) Devrait être le groupe 2 et continue ..

mais en donnant le?: nous rendons le groupe de correspondance non capturé (qui ne compte pas dans le groupe correspondant, donc le numéro de groupe commence à partir du premier groupe capturé et non le non capturé), de sorte que la répétition du résultat du match -group (?: animal) ne peut pas être appelé plus tard dans le code.

Espérons que cela explique l'utilisation du groupe non capturant.

entrez la description de l'image ici


8
2018-01-19 11:36



Eh bien, je suis un développeur JavaScript et je vais essayer d'expliquer sa signification en ce qui concerne JavaScript.

Envisagez un scénario dans lequel vous souhaitez correspondre cat is animal quand vous voulez correspondre chat et animal et les deux devraient avoir un is entre eux.

 // this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]

 // using lookahead pattern it will match only "cat" we can
 // use lookahead but the problem is we can not give anything
 // at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]

 //so I gave another grouping parenthesis for animal
 // in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]

 // we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]

6
2018-03-01 09:43



Dans les expressions régulières complexes, vous pouvez avoir la situation où vous souhaitez utiliser un grand nombre de groupes dont certains sont là pour la correspondance de répétition et certains d'entre eux sont là pour fournir des références arrières. Par défaut, le texte correspondant à chaque groupe est chargé dans le tableau de référence arrière. Lorsque nous avons beaucoup de groupes et que nous devons seulement en référencer certains d'entre eux, nous pouvons remplacer ce comportement par défaut pour indiquer à l'expression régulière que certains groupes ne sont disponibles que pour la répétition et n'ont pas besoin d'être capturés et stockés dans le tableau de référence arrière.


5
2018-03-08 17:33



Une chose intéressante que j'ai rencontrée est le fait que vous pouvez avoir un groupe de capture à l'intérieur d'un groupe non-capturant. Jetez un oeil à ci-dessous regex pour les urls web correspondant:

var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

Entrer l'URL de la chaîne:

var url = "http://www.ora.com:80/goodparts?q#fragment";

Le premier groupe de mon regex (?:([A-Za-z]+):) est un groupe non-capture qui correspond au protocole et au côlon : caractère c'est-à-dire http: mais quand je courais sous le code, je voyais le 1er index du tableau retourné contenait la chaîne http quand je pensais que http et le côlon : les deux ne seront pas signalés car ils sont à l'intérieur d'un groupe non-capturant.

console.debug(parse_url_regex.exec(url));

enter image description here

Je pensais que si le premier groupe (?:([A-Za-z]+):) est un groupe non-capture alors pourquoi il revient http chaîne dans le tableau de sortie.

Donc, si vous remarquez qu'il y a un groupe imbriqué ([A-Za-z]+) à l'intérieur du groupe non-capturant. Ce groupe imbriqué ([A-Za-z]+) est un groupe de capture (ne pas avoir ?: au début) en soi à l'intérieur d'un groupe non-capturant (?:([A-Za-z]+):). Voilà pourquoi le texte http est encore capturé, mais le côlon : Le caractère qui se trouve à l'intérieur du groupe qui ne capture pas mais à l'extérieur du groupe de capture n'est pas signalé dans le tableau de sortie.


4
2017-07-15 03:13



tl; dr groupes non-capturants, comme son nom l'indique, sont les parties de l'expression rationnelle que vous ne voulez pas inclure dans le match et ?: est un moyen de définir un groupe comme étant non-capturant.

Disons que vous avez une adresse e-mail example@example.com. L'expression régulière suivante va créer deux groupes, la partie id et la partie @ example.com. (\p{Alpha}*[a-z])(@example.com). Pour simplifier, nous extrayons tout le nom de domaine, y compris le @ personnage.

Maintenant, disons, vous avez seulement besoin de la partie id de l'adresse. Ce que vous voulez faire est de saisir le premier groupe du résultat du match, entouré par () dans la regex et la manière de le faire est d'utiliser la syntaxe de groupe sans capture, c'est-à-dire ?:. Donc, l'expression rationnelle (\p{Alpha}*[a-z])(?:@example.com) retournera juste la partie id de l'email.


3
2018-05-11 05:27