Regular Expressions
Tillbaka referens
Sök…
Grunderna
Bakreferenser används för att matcha samma text som tidigare matchats av en bildgrupp. Detta hjälper båda till att återanvända tidigare delar av mönstret och säkerställa två delar av en strängmatchning.
Om du till exempel försöker verifiera att en sträng har en siffra från noll till nio, en separator, som bindestreck, snedstreck eller till och med mellanslag, en liten bokstav, en annan separator, sedan en annan siffra från noll till nio, kan du använd en regex som denna:
[0-9][-/ ][a-z][-/ ][0-9]
Detta skulle matcha 1-a-4
, men det skulle också matcha 1-a/4
eller 1 a-4
. Om vi vill att separatorerna ska matcha kan vi använda en fångstgrupp och en bakreferens. Bakreferensen kommer att titta på matchen som finns i den indikerade fångstgruppen och se till att platsen för bakreferensen matchar exakt.
Med samma exempel skulle regexen bli:
[0-9]([-/ ])[a-z]\1[0-9]
\1
betecknar den första bildgruppen i mönstret. Med denna lilla förändring matchar regexet nu 1-a-4
eller 1 a 4
men inte 1 a-4
eller 1-a/4
.
Antalet du vill använda för din ryggreferens beror på platsen för din fångstgrupp. Antalet kan vara från en till nio och kan hittas genom att räkna dina fångstgrupper.
([0-9])([-/ ])[a-z][-/ ]([0-9])
|--1--||--2--| |--3--|
Kapslade fångstgrupper ändrar det här antalet något. Du räknar först den yttre infångningsgruppen, sedan nästa nivå och fortsätter tills du lämnar boet:
(([0-9])([-/ ]))([a-z])
|--2--||--3--|
|-------1------||--4--|
Tvetydiga bakreferenser
Problem: Du måste matcha text i ett visst format, till exempel:
1-a-0
6/p/0
4 g 0
Det är en siffra, en separator (en av -
, /
eller ett mellanslag), en bokstav, samma separator och en noll.
Naiv lösning: Anpassa regex från Basics-exemplet och du kommer med detta regex:
[0-9]([-/ ])[a-z]\10
Men det fungerar förmodligen inte. De flesta regex-smaker stödjer mer än nio fångargrupper, och väldigt få av dem är tillräckligt smarta för att inse att eftersom det bara finns en fångargrupp måste \10
vara en bakreferens till grupp 1 följt av en bokstavlig 0
. De flesta smaker kommer att behandla det som en backreference till grupp 10. Några av dem kommer att kasta ett undantag eftersom det inte finns någon grupp 10; resten kommer helt enkelt inte att matcha.
Det finns flera sätt att undvika detta problem. Den ena är att använda namngivna grupper (och namngivna bakreferenser):
[0-9](?<sep>[-/ ])[a-z]\k<sep>0
Om ditt regex-språk stöder det, kan formatet \g{n}
(där n
är ett nummer) omsluta backreferensnumret i lockiga parenteser för att skilja det från alla siffror efter det:
[0-9]([-/ ])[a-z]\g{1}0
Ett annat sätt är att använda utökad regex-formatering, separera elementen med obetydligt mellanrum (i Java måste du undvika utrymmet i parenteserna):
(?x) [0-9] ([-/ ]) [a-z] \1 0
Om din regex-smak inte stöder dessa funktioner kan du lägga till onödiga men ofarliga syntax, som en grupp som inte fångar:
[0-9]([-/ ])[a-z](?:\1)0
... eller en dummy-kvantifierare (detta är kanske den enda omständigheten där {1}
är användbar):
[0-9]([-/ ])[a-z]\1{1}0