Veiledning for å rømme tegn i Java RegExps

1. Oversikt

API for regulære uttrykk i Java, java.util.regex brukes mye til mønstermatching. For å oppdage mer, kan du følge denne artikkelen.

I denne artikkelen vil vi fokusere på å unnslippe tegn med et vanlig uttrykk og vise hvordan det kan gjøres i Java.

2. Spesielle RegExp-tegn

I henhold til API-dokumentasjonen for Java-regulære uttrykk er det et sett med spesialtegn, også kjent som metategn som er tilstede i et vanlig uttrykk.

Når vi vil tillate karakterene som de er i stedet for å tolke dem med deres spesielle betydninger, må vi unnslippe dem. Ved å unnslippe disse tegnene, tvinger vi dem til å bli behandlet som vanlige tegn når vi matcher en streng med et gitt regulært uttrykk.

Metategnene som vi vanligvis trenger for å unnslippe på denne måten er:

La oss se på et enkelt kodeeksempel der vi matcher en inngang String med et mønster uttrykt i et vanlig uttrykk.

Denne testen viser at for en gitt inngangsstreng foof når mønsteret foo. (foo som slutter med et prikktegn) matches, returnerer den verdien ekte noe som indikerer at kampen er vellykket.

@Test offentlig ugyldig gittRegexWithDot_whenMatchingStr_thenMatches () {String strInput = "foof"; Streng strRegex = "foo."; assertEquals (true, strInput.matches (strRegex)); }

Du lurer kanskje på hvorfor er kampen vellykket når det ikke er noen prikk (.) Tegn til stede i inngangen String?

Svaret er enkelt. Prikken (.) Er en metakarakter - den spesielle betydningen av prikken her er at det kan være 'hvilket som helst tegn' i stedet. Derfor er det klart hvordan matcheren bestemte at en kamp ble funnet.

La oss si at vi ikke ønsker å behandle punktet (.) Med sin unike betydning. I stedet vil vi at den skal tolkes som et prikkeskilt. Dette betyr at i det forrige eksemplet ønsker vi ikke å la mønsteret foo. å ha en kamp i innspillet String.

Hvordan ville vi håndtere en situasjon som denne? Svaret er: vi trenger å unnslippe punktet (.), slik at dets spesielle betydning blir ignorert.

La oss grave nærmere inn på det i neste avsnitt.

3. Unnslippe tegn

I følge Java API-dokumentasjonen for vanlige uttrykk er det to måter vi kan unnslippe tegn som har spesiell betydning. Med andre ord å tvinge dem til å bli behandlet som vanlige tegn.

La oss se hva de er:

  1. Gå foran en metategn med tilbakeslag (\)
  2. Legg ved en metategn med \ Q og \ E

Dette betyr bare at i eksemplet vi så tidligere, hvis vi vil unnslippe punkttegnet, må vi sette et tilbakeslagstegn foran punkttegnet. Alternativt kan vi plassere punkttegnet mellom \ Q og \ E.

3.1. Rømmer ved hjelp av tilbakeslag

Dette er en av teknikkene vi kan bruke for å unnslippe metategn i et vanlig uttrykk. Vi vet imidlertid at tilbakeslagstegnet er et flukttegn i Java String bokstavelige også. Derfor må vi doble tilbakeslagstegnet når vi bruker det for å gå foran et hvilket som helst tegn (inkludert selve \ tegnet).

Derfor må vi i vårt eksempel endre det regulære uttrykket som vist i denne testen:

@Test offentlig ugyldig gittRegexWithDotEsc_whenMatchingStr_thenNotMatching () {String strInput = "foof"; Streng strRegex = "foo \."; assertEquals (false, strInput.matches (strRegex)); }

Her unnslippes prikkkarakteren, så matcheren behandler det bare som en prikk og prøver å finne et mønster som slutter med prikken (dvs. foo.).

I dette tilfellet kommer den tilbake falsk siden det ikke er samsvar i innspillene String for det mønsteret.

3.2. Rømmer ved hjelp av \ Q & \ E

Alternativt kan vi bruke \ Q og \ E for å unnslippe spesialtegnet. \ Q indikerer at alle tegn opp til \ E må rømmes og \ E betyr at vi må avslutte rømningen som ble startet med \ Q.

Dette betyr bare at det som er mellom \ Q og \ E ville bli rømt.

I testen vist her, dele() av String klasse gjør en kamp ved å bruke det regulære uttrykket som blir gitt til den.

Vårt krav er å dele inndatastrengen av pipetegnet (|) i ord. Derfor bruker vi et vanlig uttrykksmønster for å gjøre det.

Rørkarakteren er en metakarakter som må unnslippes i det vanlige uttrykket.

Her gjøres rømningen ved å plassere rørkarakteren mellom \ Q og \ E:

@Test offentlig ugyldig gittRegexWithPipeEscaped_whenSplitStr_thenSplits () \ E "; assertEquals (4, strInput.split (strRegex) .length); 

4. Den Mønster. Sitat (streng S) Metode

The Pattern.Quote (String S) Metoden i java.util.regex.Mønster klasse konverterer et gitt regulært uttrykksmønster String inn i et bokstavelig mønster String. Dette betyr at alle metategn i inngangen String blir behandlet som vanlige karakterer.

Å bruke denne metoden vil være et mer praktisk alternativ enn å bruke \ Q & \ E når den pakker inn det gitte String med dem.

La oss se denne metoden i aksjon:

@Test offentlig ugyldig gittRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits () bar

I denne raske testen, Pattern.quote () metoden brukes for å unnslippe det gitte regex-mønsteret og transformere det til et String bokstavelig. Med andre ord, det unnslipper alle metategnene som er tilstede i regex-mønsteret for oss. Det gjør en lignende jobb som \ Q & \ E.

Rørkarakteren er rømt av Pattern.quote () metoden og dele() tolker det som en String bokstavelig som den deler inngangen med.

Som vi kan se, er dette en mye renere tilnærming, og utviklerne trenger ikke å huske alle rømningssekvensene.

Vi bør merke oss det Mønster. Sitat omslutter hele blokken med en enkelt rømningssekvens. Hvis vi ønsket å unnslippe tegn hver for seg, måtte vi bruke en algoritme for erstatning av token.

5. Ytterligere eksempler

La oss se på hvordan erstatt alle () Metode av java.util.regex.Matcher virker.

Hvis vi trenger å erstatte alle forekomster av en gitt karakter String med en annen kan vi bruke denne metoden ved å gi et vanlig uttrykk til den.

Tenk deg at vi har et innspill med flere forekomster av $ karakter. Resultatet vi ønsker å få er den samme strengen med $ karakter erstattet av £.

Denne testen demonstrerer hvordan mønsteret $ passeres uten å bli rømt:

@Test offentlig ugyldig givenRegexWithDollar_whenReplacing_thenNotReplace () {String strInput = "Jeg ga $ 50 til min bror." + "Han kjøpte godteri for $ 35. Nå har han $ 15 igjen."; Streng strRegex = "$"; Streng strReplacement = "£"; Strengutgang = "Jeg ga £ 50 til min bror." + "Han kjøpte godteri for £ 35. Nå har han £ 15 igjen."; Mønster p = Mønster.kompilere (strRegex); Matcher m = p.matcher (strInput); assertThat (output, not (equalTo (m.replaceAll (strReplacement)))); }

Testen hevder det $ erstattes ikke riktig av £.

Nå hvis vi unnslipper regex-mønsteret, skjer erstatningen riktig, og testen går som vist i dette kodebiten:

@Test public void givenRegexWithDollarEsc_whenReplacing_thenReplace () {String strInput = "Jeg ga $ 50 til min bror." + "Han kjøpte godteri for $ 35. Nå har han $ 15 igjen."; Streng strRegex = "\ $"; Streng strReplacement = "£"; Strengutgang = "Jeg ga £ 50 til min bror." + "Han kjøpte godteri for £ 35. Nå har han £ 15 igjen."; Mønster p = Mønster.kompilere (strRegex); Matcher m = p.matcher (strInput); assertEquals (output, m.replaceAll (strReplacement)); }

Legg merke til \\$ her, som gjør susen ved å unnslippe $ karakter og vellykket samsvarende med mønsteret.

6. Konklusjon

I denne artikkelen så vi på rømming av tegn i regulære uttrykk i Java.

Vi diskuterte hvorfor regelmessige uttrykk må unnslippes, og de forskjellige måtene det kan oppnås på.

Som alltid kan kildekoden relatert til denne artikkelen finnes på GitHub.