Regular Expressions
Riferimento posteriore
Ricerca…
Nozioni di base
I riferimenti posteriori vengono utilizzati per abbinare lo stesso testo precedentemente abbinato a un gruppo di cattura. Questo aiuta sia a riutilizzare parti precedenti del tuo modello sia a garantire due pezzi di una corrispondenza di stringa.
Ad esempio, se stai cercando di verificare che una stringa abbia una cifra da zero a nove, un separatore, come trattini, barre o spazi, una lettera minuscola, un altro separatore, quindi un'altra cifra da zero a nove, potresti usa una espressione regolare come questa:
[0-9][-/ ][a-z][-/ ][0-9]
Questo corrisponderebbe a 1-a-4
, ma corrisponderebbe anche a 1-a/4
o 1 a-4
. Se vogliamo che i separatori corrispondano, possiamo usare un gruppo di cattura e un riferimento alla parte posteriore. Il riferimento posteriore esaminerà la corrispondenza trovata nel gruppo di cattura indicato e si assicurerà che la posizione del riferimento posteriore corrisponda esattamente.
Usando il nostro stesso esempio, la regex diventerebbe:
[0-9]([-/ ])[a-z]\1[0-9]
Il \1
indica il primo gruppo di cattura nel modello. Con questa piccola modifica, la regex ora corrisponde a 1-a-4
o 1 a 4
ma non a 1 a-4
o 1-a/4
.
Il numero da utilizzare per il riferimento posteriore dipende dalla posizione del gruppo di acquisizione. Il numero può essere compreso tra uno e nove e può essere trovato contando i gruppi di cattura.
([0-9])([-/ ])[a-z][-/ ]([0-9])
|--1--||--2--| |--3--|
I gruppi di cattura annidati cambiano leggermente questo conteggio. Per prima cosa conta il gruppo di acquisizione esterno, quindi il livello successivo e continua fino a quando non esci dal nido:
(([0-9])([-/ ]))([a-z])
|--2--||--3--|
|-------1------||--4--|
Backreferences ambigue
Problema: è necessario abbinare il testo di un determinato formato, ad esempio:
1-a-0
6/p/0
4 g 0
Questa è una cifra, un separatore (uno di -
, /
, o uno spazio), una lettera, lo stesso separatore e uno zero.
Soluzione ingenua: adattando la regex dell'esempio di base , si arriva a questa regex:
[0-9]([-/ ])[a-z]\10
Ma probabilmente non funzionerà. La maggior parte degli aromi regex supportano più di nove gruppi di cattura, e pochissimi sono abbastanza intelligenti da rendersi conto che, poiché esiste un solo gruppo di cattura, \10
deve essere un riferimento al gruppo 1 seguito da uno 0
letterale. La maggior parte degli aromi li tratterà come un retrocesso del gruppo 10. Alcuni di questi genereranno un'eccezione perché non c'è un gruppo 10; il resto semplicemente non riuscirà a eguagliare.
Esistono diversi modi per evitare questo problema. Uno è quello di utilizzare i gruppi denominati (e le relative chiamate di ritorno):
[0-9](?<sep>[-/ ])[a-z]\k<sep>0
Se il tuo linguaggio regex lo supporta, il formato \g{n}
(dove n
è un numero) può racchiudere il numero di riferimento in parentesi graffe per separarlo da qualsiasi cifra dopo di esso:
[0-9]([-/ ])[a-z]\g{1}0
Un altro modo è usare la formattazione estesa delle espressioni regolari, separando gli elementi con spazi bianchi insignificanti (in Java è necessario sfuggire allo spazio tra parentesi):
(?x) [0-9] ([-/ ]) [a-z] \1 0
Se il tuo sapore regex non supporta queste caratteristiche, puoi aggiungere sintassi non necessaria ma innocua, come un gruppo non catturante:
[0-9]([-/ ])[a-z](?:\1)0
... o un quantificatore fittizio (questa è probabilmente l'unica circostanza in cui {1}
è utile):
[0-9]([-/ ])[a-z]\1{1}0