Ce qui est un non-capture d'un groupe? Ce n' (?:)?
14 réponses
laissez-moi essayer d'expliquer cela avec un exemple.
considérons le texte suivant:
http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex
maintenant, si j'applique le regex ci-dessous dessus...
(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
... J'obtiendrais le résultat suivant:
Match "http://stackoverflow.com/"
Group 1: "http"
Group 2: "stackoverflow.com"
Group 3: "/"
Match "https://stackoverflow.com/questions/tagged/regex"
Group 1: "https"
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 le regex pour inclure le groupe de non-capture (?:)
.
(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?
Maintenant, mon résultat ressemble à ceci:
Match "http://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 utilise pour le texte, mais l'ignore plus tard, dans le résultat final.
EDIT:
comme demandé, laissez-moi essayer d'expliquer les groupes aussi.
Eh bien, les groupes servent de nombreuses fins. Ils peuvent vous aider à extraire des informations exactes d'un plus grand match (qui peut aussi être nommé), ils vous permettent de relancer un groupe précédemment apparié, et peuvent être utilisés pour les substitutions. Essayons quelques exemples, d'accord?
OK, imaginez que vous avez une sorte de XML ou HTML (soyez conscient que regex peut ne pas être le meilleur outil pour le travail , mais il est agréable comme un exemple). Vous souhaitez analyser les balises, donc vous pourriez faire quelque chose comme ceci (j'ai ajouté des espaces pour le rendre plus facile à comprendre):
\<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
\<(.+?)\> [^<]*? \</\>
le premier regex a un groupe nommé (TAG), tandis que le second utilise un groupe commun. Les deux regexes 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'indice de groupe (qui commence à 1).
essayons quelques substitutions maintenant. Considérons le texte suivant:
Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.
maintenant, utilisons
\b(\S)(\S)(\S)(\S*)\b
ce regex correspond aux mots avec 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...
__
... de plus, nous essayons d'utiliser le premier groupe, ajouter un trait de soulignement, utilisez le troisième groupe, puis le deuxième groupe, ajouter un autre trait de soulignement, et puis le quatrième groupe. Le chaîne résultante serait comme celui 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 aussi utiliser les groupes nommés pour les substitutions, en utilisant ${name}
.
pour jouer avec les regexes, je recommande http://regex101.com / , qui offre une bonne quantité de détails sur le fonctionnement du regex; il offre également quelques moteurs regex à choisir.
vous pouvez utiliser la capture de groupes pour organiser et analyser une expression. Un groupe non-capturant a le premier avantage, mais n'a pas les frais généraux du second. Vous pouvez toujours dire qu'un groupe non capturé est optionnel, par exemple.
dit que vous voulez correspondre au texte numérique, mais certains nombres peuvent être écrits comme 1, 2, 3, 4,... Si vous voulez capturer la partie numérique, mais pas le suffixe (optionnel), vous pouvez utiliser un groupe non-capturing.
([0-9]+)(?:st|nd|rd|th)?
qui correspondra aux numéros de la forme 1, 2, 3... ou dans la forme 1, 2, 3,... mais il ne capturera que la partie numérique.
?:
est utilisé lorsque vous souhaitez une expression, mais vous ne voulez pas enregistrer en tant que appariés/capturé partie de la chaîne.
un exemple serait quelque chose pour correspondre à une adresse IP:
/(?:\d{1,3}\.){3}\d{1,3}/
notez que je ne me soucie pas de sauvegarder les 3 premiers octets, mais le groupement (?:...)
me permet de raccourcir le regex sans encourir la charge de capturer et de stocker une correspondance.
il rend le groupe non-capturing, ce qui signifie que le substrat correspondant à ce groupe ne sera pas inclus dans la liste des captures. Un exemple dans ruby pour illustrer la différence:
"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
MOTIVATION historique: l'existence de groupes non-capturants peut être expliquée par l'utilisation de parenthèses. Considérons les expressions (A|b)c et a | bc, en raison de la priorité de la concaténation sur/, ces expressions représentent deux langues différentes ({ac, bc} et {a, bc} respectivement). Cependant, les parenthèses sont utilisées aussi comme un groupe correspondant (comme expliqué par les autres réponses...).
quand vous voulez avoir la parenthèse mais ne pas capturer la sous-expression que vous utilisez NON-CAPTURING GROUPS. Dans l'exemple, (?: a / b) c
groupe que capture vous pouvez utiliser plus tard dans le regex pour correspondre à ou vous pouvez les utiliser dans la partie de remplacement du regex. Le fait de rendre un groupe Non capturable dispense simplement ce groupe d'être utilisé pour l'une ou l'autre de ces raisons.
Non-capture de groupes sont très bien si vous êtes en essayant de capturer beaucoup de choses différentes et il y a quelques 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, apprenez sur groupes atomiques , ils font beaucoup! Il y a aussi des groupes lookaround, mais ils sont un peu plus complexes et pas tellement utilisés.
exemple d'utilisation ultérieure dans le regex (backreference):
<([A-Z][A-Z0-9]*)\b[^>]*>.*?</>
[ Trouve une balise xml (sans ns de soutien) ]
([A-Z][A-Z0-9]*)
est un groupe de capture (dans ce cas c'est le tagname)
plus tard dans le regex est ce qui signifie qu'il ne correspondra qu'au même texte qui était dans le premier groupe (le groupe
([A-Z][A-Z0-9]*)
) (dans ce cas, il correspond à l'étiquette de fin).
laissez-moi essayer avec un exemple: -
Code Regex: - (?:animal)(?:=)(\w+)(,)
Chaîne De Recherche: -
ligne 1 - animal=cat,dog,cat,tiger,dog
ligne 2 - animal=cat,cat,dog,dog,tiger
ligne 3 - animal=dog,dog,cat,cat,tiger
(?:animal)
--> Non Saisis Groupe 1
(?:=)
--> Non Saisis Groupe 2
(\w+)
-- > capturé Groupe 1
(,)
-- > Capturé Groupe 2
-- > résultat de la capture du Groupe 1 I. e dans la ligne 1 est cat,dans la ligne 2 est cat,dans la ligne 3 est dog.
-- > résultat de la capture du groupe 2 I. e virgule (,)
ainsi dans ce code en donnant \1 et \2 nous rappelons ou répétons le résultat des groupes 1 et 2 capturés respectivement plus tard dans le code.
selon l'ordre de code (?: animal) devrait être le groupe 1 et (?:=) devrait être le groupe 2 et continue..
mais en donnant le ?: nous faisons le groupe de match non capturé(qui ne comptent pas dans le groupe de match, donc le nombre de groupage commence à partir du premier groupe capturé et non le non capturé), de sorte que la répétition du résultat du groupe de match (?: animal) ne peut pas être appelé plus tard en code.
l'Espoir c'est ce qui explique la non-utilisation de la capture de groupe.
Eh bien je suis un développeur JavaScript et vais essayer d'expliquer son importance relative à JavaScript.
imaginez un scénario où vous voulez match cat is animal
quand vous voulez assortir le chat et l'animal et tous 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"]
dans les expressions régulières complexes, vous pouvez vous trouver dans une situation où vous souhaitez utiliser un grand nombre de groupes, dont certains sont là pour la correspondance répétitive et d'autres pour fournir des références rétrospectives. Par défaut, le texte correspondant à chaque groupe est chargé dans le tableau backreference. Lorsque nous avons beaucoup de groupes et que nous n'avons besoin que de référencer certains d'entre eux à partir du tableau backreference, nous pouvons outrepasser ce comportement par défaut pour dire à l'expression régulière que certains groupes ne sont là que pour la manipulation de la répétition et n'ont pas besoin d'être capturés et stockés dans le tableau backreference.
une chose intéressante que je suis tombé sur est le fait que vous pouvez avoir un groupe de capture à l'intérieur d'un groupe de non-capture. Regardez ci-dessous regex pour trouver les urls web correspondantes:
var parse_url_regex = /^(?:([A-Za-z]+):)(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
chaîne d'url D'entrée:
var url = "http://www.ora.com:80/goodparts?q#fragment";
le premier groupe dans mon regex (?:([A-Za-z]+):)
est un groupe non-capturant qui correspond au schéma de protocole et au caractère :
c'est-à-dire http:
mais quand je courais sous le code, je voyais le Le 1er index du tableau retourné contenait la chaîne http
quand je pensais que http
et :
tous les deux ne seront pas déclarés car ils sont à l'intérieur d'un groupe de non-capture.
console.debug(parse_url_regex.exec(url));
j'ai pensé que si le premier groupe (?:([A-Za-z]+):)
est un groupe non-capturant alors pourquoi il renvoie 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 (n'ayant pas ?:
au début) en lui-même à l'intérieur d'un groupe de non-capture (?:([A-Za-z]+):)
. C'est pourquoi le texte http
est toujours capturé, mais le caractère :
qui est à l'intérieur du groupe non-capturing mais à l'extérieur du groupe capturing n'est pas signalé dans le tableau de sortie.
Je ne peux pas commenter les réponses supérieures pour dire ceci: je voudrais ajouter un point explicite qui est seulement implicite dans les réponses supérieures:
Le non-capture d'un groupe (?...)
est-ce que ne supprime pas tous les caractères de la correspondance originale, il seulement réorganise visuellement le regex au programmeur.
pour accéder à une partie spécifique du regex sans caractères étrangers définis, vous devez toujours besoin d'utiliser .group(<index>)
tl;dr non-capture de groupes, comme son nom l'indique, sont les parties de l'expression régulière que vous ne voulez pas être inclus dans le match et ?:
est une façon de définir un groupe comme étant non-capture.
disons que vous avez une adresse email example@example.com
. Le regex suivant créera deux groupes , la partie id et @example.com part. (\p{Alpha}*[a-z])(@example.com)
. Pour plus de simplicité, nous extrayons le nom de domaine entier y compris le caractère @
.
maintenant, disons que vous n'avez besoin que de la partie id de l'adresse. Ce que vous voulez faire est de saisir le premier groupe du résultat de correspondance, entouré par ()
dans le regex et la façon de le faire est d'utiliser la syntaxe de groupe non-capturing, i.e. ?:
. Ainsi le regex (\p{Alpha}*[a-z])(?:@example.com)
retournera juste la partie id de l'email.
je pense que je vous donnerais la réponse, N'utilisez pas de variables de capture sans vérifier que la correspondance a réussi.
les variables de capture, $1, etc, ne sont pas valides sauf si la correspondance a réussi, et ils ne sont pas effacés, non plus.
#!/usr/bin/perl
use warnings;
use strict;
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
print "Fred wants a ";
}
else
{
print "Fred dont wants a ";
}
dans l'exemple ci-dessus, pour éviter de capturer bronto en $1, (?:) est utilisé. Si le modèle est apparié, alors $1 est capturé comme prochain modèle groupé. Donc, la sortie sera comme ci-dessous:
Fred wants a burger
Il est Utile si vous ne voulez pas les matchs pour être sauvé .
ouvrez votre Google Chrome devTools, puis L'onglet Console: et tapez ceci:
"Peace".match(/(\w)(\w)(\w)/)
lancez-le et vous verrez:
["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]
le moteur JavaScript
RegExp capture trois groupes, les éléments avec des index 1,2,3. Maintenant, utilisez la marque non-capturing pour voir le résultat.
"Peace".match(/(?:\w)(\w)(\w)/)
le résultat est:
["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]
c'est évident ce qui n'est pas un groupe de capture.