Domanda

Come vengono gruppi non-cattura, vale a dire (?:), usati nelle espressioni regolari e che cosa sono buone per?

È stato utile?

Soluzione

Vorrei cercare di spiegare con un esempio.

Si consideri il seguente testo:

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

Ora, se applico la regex di sotto sopra ...

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

... Mi sarebbe ottenere il seguente risultato:

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"

Ma non mi interessa circa il protocollo - voglio solo l'host e il percorso dell'URL. Quindi, io cambio la regex per includere il non-cattura (?:) gruppo.

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

Ora, il mio aspetto risultato come questo:

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"

Vedi? Il primo gruppo non è stato catturato. Gli usi parser modo che corrisponda al testo, ma lo ignora più tardi, nel risultato finale.


EDIT:

Come richiesto, mi permetta di provare a spiegare i gruppi troppo.

Bene, gruppi servono vari scopi. Possono aiutare a estrarre informazioni esatte da una partita più grande (che può anche essere chiamato), essi consentono di rivincita di un gruppo abbinato precedente, e possono essere utilizzati per sostituzioni. Proviamo alcuni esempi, che ne dite?

Ok, immaginate di avere un qualche tipo di XML o HTML (essere consapevoli che espressione regolare non può essere lo strumento migliore per il lavoro , ma è bello come un esempio). Si vuole analizzare i tag, così si potrebbe fare qualcosa di simile (ho aggiunto gli spazi per rendere più facile da capire):

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

La prima regex ha un gruppo di nome (TAG), mentre il secondo utilizza un gruppo comune. Entrambe le espressioni regolari fanno la stessa cosa: usano il valore dal primo gruppo (il nome del tag) per abbinare il tag di chiusura. La differenza è che il primo utilizza il nome corrisponda al valore, e il secondo utilizza l'indice del gruppo (che inizia a 1).

Proviamo alcune sostituzioni ora. Si consideri il seguente testo:

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

Ora, usiamo questa espressione regolare muto su di esso:

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

Questo corrisponde all'espressione regolare le parole con almeno 3 caratteri e gruppi di usi per separare le prime tre lettere. Il risultato è questo:

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"
...

Quindi, se applichiamo la stringa di sostituzione:

$1_$3$2_$4

... su di esso, stiamo cercando di utilizzare il primo gruppo, aggiungere un carattere di sottolineatura, utilizzare il terzo gruppo, poi il secondo gruppo, aggiungere un altro di sottolineatura, e poi il quarto gruppo. La stringa risultante sarebbe come quella qui sotto.

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.

È possibile utilizzare i gruppi chiamato per le sostituzioni troppo, utilizzando ${name}.

Per giocare con regex, vi consiglio http://regex101.com/ , che offre una buona quantità di dettagli su come funziona l'espressione regolare; offre anche un paio di motori regex da scegliere.

Altri suggerimenti

È possibile utilizzare gruppi di cattura per organizzare e analizzare un'espressione. Un gruppo non-cattura ha il primo vantaggio, ma non ha l'overhead del secondo. Si può ancora dire un gruppo non-cattura è facoltativo, per esempio.

Dire che si desidera abbinare il testo numerico, ma alcuni numeri potrebbe essere scritto come 1 °, 2 °, 3 °, 4 °, ... Se si desidera catturare la parte numerica, ma non il suffisso (opzionale) è possibile utilizzare un non gruppo -capturing.

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

che abbinerà i numeri nella forma 1, 2, 3 ... o sotto forma 1 °, 2 °, 3 °, ... ma sarà catturare solo la parte numerica.

?: viene utilizzato quando si desidera raggruppare un'espressione, ma non si vuole salvarlo come / porzione catturata abbinato della stringa.

Un esempio potrebbe essere qualcosa per abbinare un indirizzo IP:

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

Si noti che non mi interessa di salvare i primi 3 ottetti, ma il raggruppamento (?:...) mi permette di accorciare la regex senza incorrere l'overhead di catturare e immagazzinare un match.

Si rende il gruppo non-cattura, il che significa che la stringa corrispondente al gruppo che non sarà incluso nella lista delle catture. Un esempio in Ruby per illustrare la differenza:

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

motivazione storica: L'esistenza di gruppi non-cattura può essere spiegato con l'uso delle parentesi. Considerate le espressioni (a | b) c ed un | bc, a causa di priorità del concatenamento sopra |, queste espressioni rappresentano due lingue diverse ({ac, bc} e {a, bc} rispettivamente). Tuttavia, la parentesi sono utilizzati anche come un gruppo di corrispondenza (come spiegato dalle altre risposte ...).

Quando si desidera avere parentesi ma non catturare l'sottoespressione si utilizza gruppi non-cattura. Nell'esempio, (:? Un | b) c

I gruppi che cattura è possibile utilizzare più tardi nel regex per abbinare o è possibile utilizzarli nella parte sostituzione del regex. Fare un non cattura gruppo esenta semplicemente che gruppo sia utilizzato per uno di questi motivi.

gruppi non-cattura sono grandi se si sta cercando di catturare molte cose diverse e ci sono alcuni gruppi che non si desidera catturare.

Questo è più o meno la ragione per cui esiste. Mentre si sta imparando sui gruppi, conoscere atomica Gruppi , fanno un sacco! Ci sono anche gruppi di Lookaround ma sono un po 'più complesso e non utilizzati tanto.

Esempio di utilizzo più avanti nel regolare (backreference):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [Finds un tag XML (senza supporto ns)]

([A-Z][A-Z0-9]*) è un gruppo di cattura (in questo caso è la TagName)

Più tardi nel regex è \1 che significa che corrisponderà solo lo stesso testo che era nel primo gruppo (il gruppo ([A-Z][A-Z0-9]*)) (in questo caso si sta abbinando il tag finale).

Fammi provare questo con un esempio: -

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

Stringa di ricerca: -

Linea 1 - animal=cat,dog,cat,tiger,dog

Linea 2 - animal=cat,cat,dog,dog,tiger

Linea 3 - animal=dog,dog,cat,cat,tiger

(?:animal) -> Non Captured Gruppo 1

(?:=) -> Non Captured Gruppo 2

(\w+) -> Captured gruppo 1

(,) -> Captured Gruppo 2

\1 -> risultato di gruppo catturato 1 cioè In linea 1 è il gatto, in linea 2 è il gatto, in linea 3 è cane

.

\2 -> risultato di gruppo catturato 2 cioè virgola (,)

Quindi, in questo codice, dando \ 1 e \ 2 ricordiamo o ripetere il risultato di gruppo catturato 1 e 2, rispettivamente, più avanti nel codice.

secondo l'ordine di codice (:? Animale) deve essere di gruppo 1 e (:? =) Dovrebbe essere del gruppo 2 e continua ..

, ma dando al: facciamo il non match-gruppo acquisito (che non contano fuori nel gruppo abbinato, quindi il numero di raggruppamento parte dal gruppo prima catturato e non il non catturati), in modo tale che la ripetizione del risultato di match-gruppo (:? animale). non può essere chiamato più avanti nel codice

Spero che questo spiega l'uso di gruppo non cattura.

entrare descrizione dell'immagine qui

Anche io sono uno sviluppatore JavaScript e cercherò di spiegare il suo significato di pertinenza JavaScript.

Si consideri uno scenario in cui si desidera far corrispondere cat is animal quando si desidera partita gatto e degli animali ed entrambi dovrebbe avere un is tra di loro.

 // 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"]

Nelle espressioni regolari complesse si può avere la situazione sorgono in cui si desidera utilizzare un gran numero di gruppi, alcuni dei quali ci sono per la corrispondenza di ripetizione e alcuni dei quali sono lì per fornire riferimenti all'indietro. Per default il testo corrispondente ciascun gruppo viene caricato nella matrice backreference. Dove abbiamo un sacco di gruppi e solo bisogno di essere in grado di fare riferimento a alcuni di loro dalla matrice backreference possiamo ignorare questo comportamento predefinito per dire l'espressione regolare che alcuni gruppi sono lì solo per la manipolazione ripetizione e non hanno bisogno di essere catturato e immagazzinato nell'array backreference.

Non posso commentare le migliori risposte per dire questo: Vorrei aggiungere un punto esplicito, che è implicito solo nelle migliori risposte:

Il (?...) gruppo non-cattura fa Non rimuovere i caratteri dalla partita piena originale, solo riorganizza la regex visivamente al programmatore.

Per accedere a una parte specifica del regex senza caratteri estranei definiti si sarebbe sempre necessario utilizzare .group(<index>)

tl; dr non gruppi di cattura, come suggerisce il nome sono le parti del regex che non si desidera essere inclusi nella partita e ?: è un modo per definire un gruppo come essere non cattura.

esempio di farvi avere un example@example.com indirizzo di posta elettronica. La seguente espressione regolare creerà due Gruppi , la parte ID e @ example.com parte. (\p{Alpha}*[a-z])(@example.com). Per semplicità, noi estraiamo l'intero nome di dominio compreso il carattere @.

Ora diciamo, è necessario solo la parte id dell'indirizzo. Che cosa si vuole fare è quello di afferrare il primo gruppo del risultato della partita, circondato da () nel regex e il modo per farlo è quello di utilizzare la sintassi non-gruppo di cattura, cioè ?:. Così il (\p{Alpha}*[a-z])(?:@example.com) regex restituirà solo la parte ID del email.

Una cosa interessante che ho trovato è il fatto che si può avere un gruppo di cattura all'interno di un gruppo non-cattura. Date un'occhiata al di sotto espressioni regolari per la corrispondenza URL web:

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

stringa URL in ingresso:

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

Il primo gruppo nel mio (?:([A-Za-z]+):) regex è un gruppo non-cattura che corrisponde al sistema di protocollo e del colon carattere : cioè http: ma quando ho girato al di sotto del codice, mi è stato vedere il primo indice della matrice restituita è stato che contiene la http stringa quando stavo pensando che http e del colon : entrambi non andranno segnalato come sono all'interno di un gruppo non-cattura.

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

 entrare descrizione dell'immagine qui

ho pensato che se il primo (?:([A-Za-z]+):) gruppo è un gruppo non-cattura, allora il motivo per cui sta tornando stringa http nella matrice di uscita.

Quindi, se si nota che c'è un ([A-Za-z]+) gruppo nidificato all'interno del gruppo non-cattura. Che ([A-Za-z]+) gruppo nidificato è un gruppo di cattura (non avendo ?: all'inizio) di per sé all'interno di un (?:([A-Za-z]+):) non gruppo di cattura. Ecco perché il http testo ancora, viene catturato, ma il carattere due punti : che è all'interno del gruppo non-cattura, ma al di fuori del gruppo di cattura non viene riportato nella matrice di uscita.

penso che darei la risposta, Non utilizzare le variabili di acquisizione senza verificare che la partita è riuscita.

Le variabili di cattura, $ 1, ecc, non sono validi a meno che la partita è riuscito, e non sono cancellati, sia.

#!/usr/bin/perl  
use warnings;
use strict;   
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
{
    print "Fred wants a  $1";
}
else
{
    print "Fred dont wants a $1 $2";
}

Nell'esempio di cui sopra, per evitare la cattura Bronto in $ 1, (? :) viene utilizzato. Se il modello è abbinato, allora $ 1 viene catturato dal prossimo modello raggruppati. Così, l'uscita sarà come di seguito:

Fred wants a burger

E 'utile se non si desidera che le partite siano salvati.

Aprire il Google Chrome DevTools e poi scheda Console: e digitare questo:

"Peace".match(/(\w)(\w)(\w)/)

Esegui e si vedrà:

["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]

La cattura dei motori JavaScript RegExp tre gruppi, gli elementi con indici 1,2,3. Ora utilizzare il marchio non cattura per vedere il risultato.

"Peace".match(/(?:\w)(\w)(\w)/)

Il risultato è:

["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]

Questo è evidente che cosa è il gruppo non cattura.

La sua estremamente semplice, possiamo capire con una semplice esempio la data, supponiamo che se la data è indicata come 1 Gennaio 2019 o 2 Maggio 2019 o qualsiasi altra data e noi semplicemente vuole convertirlo in gg / mm / aaaa formato che non avrebbe bisogno il nome del mese che è gennaio o febbraio per quella materia, così al fine di catturare la parte numerica, ma non il (opzionale) suffisso è possibile utilizzare un non-gruppo di cattura.

quindi l'espressione regolare sarebbe,

([0-9]+)(?:January|February)?

La sua così semplice come sembra.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top