Cos’è un gruppo non catturante? Cosa fa?

Come ?: Viene utilizzato e a cosa serve?

    Lasciatemi provare a spiegare questo con un esempio.

    Considera il seguente testo:

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

    Ora, se applico la regex sotto di essa …

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

    … Otterrei 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 il protocollo: voglio solo l’host e il percorso dell’URL. Quindi, cambio la regex per includere il gruppo non catturante (?:) .

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

    Ora, il mio risultato è il seguente:

     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" 

    Vedere? Il primo gruppo non è stato catturato. Il parser lo usa per abbinare il testo, ma lo ignora più tardi, nel risultato finale.


    MODIFICARE:

    Come richiesto, permettimi di provare a spiegare anche i gruppi.

    Bene, i gruppi servono a molti scopi. Possono aiutarti a estrarre informazioni esatte da una corrispondenza più grande (che può anche essere nominata), ti permettono di rivincere un precedente gruppo abbinato e possono essere utilizzate per le sostituzioni. Proviamo alcuni esempi, dovremmo?

    Ok, immagina di avere una sorta di XML o HTML ( tieni presente che la regex potrebbe non essere lo strumento migliore per il lavoro , ma è un buon esempio). Vuoi analizzare i tag, in modo che tu possa fare qualcosa di simile (ho aggiunto degli spazi per renderlo più facile da capire):

      \< (?.+?)\> [^< ]*? \\> or \< (.+?)\> [^< ]*? \ 

    La prima espressione regolare ha un gruppo denominato (TAG), mentre il secondo utilizza un gruppo comune. Entrambe le regex fanno la stessa cosa: usano il valore del primo gruppo (il nome del tag) in modo che corrisponda al tag di chiusura. La differenza è che il primo usa il nome per abbinare il valore, e il secondo usa l’indice di gruppo (che inizia da 1).

    Proviamo alcune sostituzioni ora. Considera il seguente testo:

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

    Ora, usiamo questa stupida regex su di essa:

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

    Questa regex corrisponde a parole con almeno 3 caratteri e utilizza i gruppi 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 

    … sopra, stiamo cercando di usare il primo gruppo, aggiungere un trattino basso, usare il terzo gruppo, poi il secondo gruppo, aggiungere un altro trattino basso e poi il quarto gruppo. La stringa risultante sarebbe simile a quella sottostante.

     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. 

    Puoi usare anche i gruppi con nome per le sostituzioni, usando ${name} .

    Per giocare con regex, consiglio http://regex101.com/ , che offre una buona quantità di dettagli su come funziona la regex; offre anche alcuni motori regex tra cui scegliere.

    È ansible utilizzare i gruppi di cattura per organizzare e analizzare un’espressione. Un gruppo non catturante ha il primo vantaggio, ma non ha il sovraccarico del secondo. Puoi ancora dire che un gruppo non catturante è opzionale, per esempio.

    Supponi di voler abbinare il testo numerico, ma alcuni numeri potrebbero essere scritti come 1 °, 2 °, 3 °, 4 ° … Se si desidera acquisire la parte numerica, ma non il suffisso (opzionale) è ansible utilizzare un gruppo non acquisibile .

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

    Ciò corrisponderà ai numeri nella forma 1, 2, 3 … o nella forma 1a, 2a, 3a, ma acquisirà solo la parte numerica.

    ?: viene utilizzato quando si desidera raggruppare un’espressione, ma non si desidera salvarlo come una porzione corrispondente / catturata 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 salvare i primi 3 ottetti, ma il raggruppamento (?:...) mi consente di abbreviare la regex senza incorrere nel sovraccarico di acquisizione e memorizzazione di una corrispondenza.

    Rende il gruppo non catturante, il che significa che la sottostringa corrispondente a quel gruppo non sarà inclusa nell’elenco 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 catturanti può essere spiegata con l’uso di parentesi. Considerare le espressioni (a | b) c e a | bc, a causa della priorità di concatenazione su |, queste espressioni rappresentano due linguaggi diversi (rispettivamente {ac, bc} e {a, bc}). Tuttavia, le parentesi vengono anche utilizzate come gruppo corrispondente (come spiegato dalle altre risposte …).

    Quando si desidera avere una parentesi ma non acquisire la sottoespressione, si usano GRUPPI NON CATTURANTI. Nell’esempio, (?: A | b) c

    I gruppi che ti catturano possono essere utilizzati in seguito nella regex per abbinarli o puoi usarli nella parte di sostituzione della regex. Fare un gruppo non catturante semplicemente esonera il gruppo dall’essere utilizzato per uno di questi motivi.

    I gruppi che non catturano sono grandi se stai cercando di catturare molte cose diverse e ci sono alcuni gruppi che non vuoi catturare.

    Questo è praticamente il motivo per cui esistono. Mentre stai imparando sui gruppi, conosci i Gruppi Atomici , loro fanno molto! Ci sono anche gruppi di ricerca, ma sono un po ‘più complessi e non sono usati così tanto.

    Esempio di utilizzo in seguito nella regex (backreference):

    < ([AZ][A-Z0-9]*)\b[^>]*>.*? [Trova un tag xml (senza supporto ns)]

    ([AZ][A-Z0-9]*) è un gruppo di cattura (in questo caso è il tagname)

    Più avanti nella regex è \1 che significa che corrisponderà solo allo stesso testo del primo gruppo (il gruppo ([AZ][A-Z0-9]*) ) (in questo caso corrisponde al tag di chiusura ).

    Fammi provare questo con un esempio: –

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

    Stringa di ricerca :-

    Linea 1 – animale = gatto, cane, gatto, tigre, cane

    Linea 2 – animale = gatto, gatto, cane, cane, tigre

    Linea 3 – animale = cane, cane, gatto, gatto, tigre

    (?:animal) -> Gruppo non catturato 1

    (?:=) -> Gruppo 2 non catturato

    (\w+) -> Catturato gruppo 1

    (,) -> Catturato Gruppo 2

    \1 -> risultato del gruppo catturato 1 vale a dire In linea 1 è gatto, In linea 2 è gatto, In linea 3 è cane.

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

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

    Secondo l’ordine del codice (?: Animale) dovrebbe essere il gruppo 1 e (?: =) Dovrebbe essere il gruppo 2 e continua ..

    ma dando il?: rendiamo il gruppo di confronto non catturato (che non contano nel gruppo abbinato, quindi il numero di raggruppamento inizia dal primo gruppo catturato e non il non catturato), in modo che la ripetizione del risultato della corrispondenza -group (?: animal) non può essere chiamato più tardi nel codice.

    Spero che questo spieghi l’uso del gruppo non catturante.

    inserisci la descrizione dell’immagine qui

    Bene, sono uno sviluppatore JavaScript e cercherò di spiegare il suo significato relativo a JavaScript.

    Considerare uno scenario in cui si desidera abbinare il cat is animal quando si desidera abbinare il gatto e l’animale e entrambi dovrebbero avere una 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 è ansible che si presenti la situazione in cui si desidera utilizzare un numero elevato di gruppi, alcuni dei quali disponibili per la ripetizione della corrispondenza e alcuni dei quali sono disponibili per fornire riferimenti. Per impostazione predefinita, il testo corrispondente a ciascun gruppo viene caricato nell’array backreference. Nei casi in cui disponiamo di molti gruppi e dobbiamo solo essere in grado di fare riferimento ad alcuni di essi dall’array backreference, possiamo sovrascrivere questo comportamento predefinito per dire all’espressione regolare che alcuni gruppi sono presenti solo per la gestione della ripetizione e non devono essere catturati e archiviati nell’array backreference.

    Una cosa interessante che ho trovato è il fatto che puoi avere un gruppo di cattura all’interno di un gruppo non catturante. Dai un’occhiata alle espressioni regolari di seguito per gli URL web corrispondenti:

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

    Stringa di url di input:

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

    Il primo gruppo nella mia regex (?:([A-Za-z]+):) è un gruppo non catturante che corrisponde allo schema del protocollo e due punti : carattere cioè http: ma quando stavo correndo sotto il codice, stavo vedendo il primo indice dell’array restituito conteneva la stringa http quando pensavo che http e due punti : entrambi non verranno segnalati come se fossero all’interno di un gruppo non catturante.

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

    inserisci la descrizione dell'immagine qui

    Ho pensato che se il primo gruppo (?:([A-Za-z]+):) è un gruppo non catturante, allora perché sta restituendo la stringa http nell’array di output.

    Quindi se noti che c’è un gruppo annidato ([A-Za-z]+) all’interno del gruppo non catturante. Quel gruppo annidato ([A-Za-z]+) è un gruppo che cattura (non avendo ?: All’inizio) di per sé all’interno di un gruppo non catturante (?:([A-Za-z]+):) . Ecco perché il testo http viene catturato ma i due punti : carattere che si trova all’interno del gruppo non catturante ma all’esterno del gruppo di acquisizione non viene segnalato nell’array di output.

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

    Supponiamo che tu abbia un indirizzo email example@example.com . La regex seguente creerà due gruppi , la parte id e la parte @ example.com. (\p{Alpha}*[az])(@example.com) . Per ragioni di semplicità, stiamo estraendo l’intero nome del dominio incluso il carattere @ .

    Ora diciamo, hai solo bisogno della parte id dell’indirizzo. Quello che vuoi fare è afferrare il primo gruppo del risultato della partita, circondato da () nella regex e il modo per farlo è usare la syntax del gruppo non catturante, cioè ?: . Quindi la regex (\p{Alpha}*[az])(?:@example.com) restituirà solo la parte id del messaggio di posta elettronica.

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

    Il gruppo non catturante (?...) non rimuove alcun carattere dalla corrispondenza originale originale, ma riorganizza visivamente il regex visivamente al programmatore.

    Per accedere a una parte specifica della regex senza caratteri estranei definiti, devi sempre utilizzare .group()

    Penso che vorrei darti la risposta, non usare le variabili di cattura senza controllare che la corrispondenza sia stata eseguita correttamente.

    Le variabili di cattura, $ 1, ecc. Non sono valide a meno che la corrispondenza non abbia avuto successo e non siano state eliminate.

     #!/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 sopra, per evitare di catturare bronto in $ 1, viene utilizzato (? :). Se il modello è abbinato, $ 1 viene catturato come modello raggruppato successivo. Quindi, l’output sarà il seguente:

     Fred wants a burger 

    È utile se non vuoi che le partite vengano salvate.

    Apri il tuo Google Chrome devTools e poi la scheda Console: e scrivi questo:

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

    Eseguilo e vedrai:

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

    Il motore RegExp JavaScript acquisisce tre gruppi, gli elementi con indici 1,2,3. Ora usa un segno non acquisibile per vedere il risultato.

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

    Il risultato è:

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

    Questo è ovvio che cos’è un gruppo non catturante.