Guide för att fly från tecken i Java RegExps

1. Översikt

API för reguljära uttryck i Java, java.util.regex används ofta för mönstermatchning. För att upptäcka mer kan du följa den här artikeln.

I den här artikeln kommer vi att fokusera på att rymma tecken med ett vanligt uttryck och visa hur det kan göras i Java.

2. Särskilda RegExp-tecken

Enligt Java-dokumentationen för Java-reguljära uttryck finns det en uppsättning specialtecken, även känd som metatecken, i ett reguljärt uttryck.

När vi vill tillåta karaktärerna som de är istället för att tolka dem med sina speciella betydelser, måste vi fly från dem. Genom att fly från dessa tecken tvingar vi dem att behandlas som vanliga tecken när vi matchar en sträng med ett givet reguljärt uttryck.

Metatecken som vi vanligtvis behöver fly på detta sätt är:

Låt oss titta på ett enkelt kodexempel där vi matchar en ingångs String med ett mönster som uttrycks i ett reguljärt uttryck.

Detta test visar att för en given ingångssträng foof när mönstret foo . ( foo som slutar med ett punktkaraktär) matchas, det returnerar värdet true som indikerar att matchningen är framgångsrik.

@Test public void givenRegexWithDot_whenMatchingStr_thenMatches() { String strInput = "foof"; String strRegex = "foo."; assertEquals(true, strInput.matches(strRegex)); }

Du kanske undrar varför är matchningen lyckad när det inte finns någon punkt (.) I ingångssträngen ?

Svaret är enkelt. Punkt (.) Är en metakaraktär - punktens speciella betydelse här är att det kan finnas 'vilken karaktär som helst' i stället. Därför är det klart hur matcharen bestämde att en matchning hittades.

Låt oss säga att vi inte vill behandla prickkaraktären (.) Med dess unika betydelse. Istället vill vi att det ska tolkas som ett prickstecken. Detta innebär att vi i det föregående exemplet inte vill låta mönstret foo. att ha en matchning i ingångssträngen .

Hur skulle vi hantera en sådan situation? Svaret är: vi måste undkomma punkt (.) -Tecknet så att dess speciella betydelse ignoreras.

Låt oss gräva mer detaljerat i nästa avsnitt.

3. Flyktande tecken

Enligt Java API-dokumentationen för reguljära uttryck finns det två sätt på vilka vi kan komma undan tecken som har speciell betydelse. Med andra ord att tvinga dem att behandlas som vanliga karaktärer.

Låt oss se vad de är:

  1. Före en metatecken med en backslash (\)
  2. Bifoga en metatecken med \ Q och \ E

Detta betyder bara att i exemplet vi såg tidigare, om vi vill undkomma prickkaraktären, måste vi sätta ett bakåtvänd snedstreck före prickkaraktären. Alternativt kan vi placera pricket mellan \ Q och \ E.

3.1. Flyr med bakåtvänd snedstreck

Detta är en av de tekniker som vi kan använda för att undkomma metatecken i ett reguljärt uttryck. Vi vet dock att backslash-karaktären också är en escape-karaktär i Java String- bokstäver. Därför måste vi fördubbla backslash-tecknet när vi använder det för att gå före vilket tecken som helst (inklusive själva \ karaktären).

Därför måste vi i vårt exempel ändra det reguljära uttrycket som visas i detta test:

@Test public void givenRegexWithDotEsc_whenMatchingStr_thenNotMatching() { String strInput = "foof"; String strRegex = "foo\\."; assertEquals(false, strInput.matches(strRegex)); }

Här undviks prickkaraktären, så matcharen behandlar den helt enkelt som en prick och försöker hitta ett mönster som slutar med pricken (dvs. foo. ).

I detta fall returneras false eftersom det inte finns någon matchning i inmatnings String för det mönstret.

3.2. Flyr med \ Q & \ E

Alternativt kan vi använda \ Q och \ E för att undkomma specialtecknet. \ Q indikerar att alla tecken upp till \ E måste flydde och \ E innebär att vi måste avsluta den utströmmande som startades med \ Q .

Detta betyder bara att vad som helst mellan \ Q och \ E skulle komma undan.

I testet som visas här gör split () i strängklassen en matchning med det reguljära uttrycket som ges till det.

Vårt krav är att dela in inmatningssträngen av rörtecken (|) i ord. Därför använder vi ett regelbundet uttrycksmönster för att göra det.

Rörkaraktären är en metatecken som måste undvikas i det reguljära uttrycket.

Här görs flykten genom att placera rörtecken mellan \ Q och \ E :

@Test public void givenRegexWithPipeEscaped_whenSplitStr_thenSplits() \\E"; assertEquals(4, strInput.split(strRegex).length); 

4. Method.quote (String S) -metoden

The Pattern.Quote (String S) Method in java.util.regex.Pattern class converts a given regular expression pattern String into a letteral pattern String. Detta innebär att alla metatecken i inmatnings String behandlas som vanliga tecken.

Att använda den här metoden skulle vara ett bekvämare alternativ än att använda \ Q & \ E eftersom det sveper den givna strängen med dem.

Låt oss se den här metoden i aktion:

@Test public void givenRegexWithPipeEscQuoteMeth_whenSplitStr_thenSplits() bar

I detta snabbtest, den Pattern.quote () är metoden som används för att fly det givna reguljära uttrycket mönstret och omvandla det till en String litteral. Med andra ord undgår det alla metatecken som finns i regexmönstret för oss. Det gör ett liknande jobb till \ Q & \ E .

Röret tecknet rymt av Pattern.quote () metoden och split () tolkar den som en sträng bokstavlig genom vilket det indelar den inmatade.

Som vi kan se är detta ett mycket renare tillvägagångssätt och utvecklarna behöver inte komma ihåg alla escape-sekvenser.

Vi bör notera att Pattern.quote omsluter hela blocket med en enda escape-sekvens. Om vi ​​ville fly karaktärer individuellt, skulle vi behöva använda en tokenersättningsalgoritm.

5. Ytterligare exempel

Låt oss titta på hur metoden replaceAll () av java.util.regex.Matcher fungerar.

Om vi behöver ersätta alla förekomster av en viss karaktär sträng med en annan, kan vi använda den här metoden genom att ett reguljärt uttryck för det.

Tänk dig att vi har en ingång med flera förekomster av $ -tecknet. Resultatet vi vill få är samma sträng med $ -tecknet ersatt med £.

Detta test visar hur mönstret $ passeras utan att undgå att undgå:

@Test public void givenRegexWithDollar_whenReplacing_thenNotReplace() { String strInput = "I gave $50 to my brother." + "He bought candy for $35. Now he has $15 left."; String strRegex = "$"; String strReplacement = "£"; String output = "I gave £50 to my brother." + "He bought candy for £35. Now he has £15 left."; Pattern p = Pattern.compile(strRegex); Matcher m = p.matcher(strInput); assertThat(output, not(equalTo(m.replaceAll(strReplacement)))); }

Testet hävdar att $ inte ersätts korrekt med £ .

Om vi ​​nu undgår regex-mönstret händer ersättningen korrekt och testet går som visas i det här kodavsnittet:

@Test public void givenRegexWithDollarEsc_whenReplacing_thenReplace() { String strInput = "I gave $50 to my brother." + "He bought candy for $35. Now he has $15 left."; String strRegex = "\\$"; String strReplacement = "£"; String output = "I gave £50 to my brother." + "He bought candy for £35. Now he has £15 left."; Pattern p = Pattern.compile(strRegex); Matcher m = p.matcher(strInput); assertEquals(output,m.replaceAll(strReplacement)); }

Observera \\ $ här, vilket gör tricket genom att fly $ -tecknet och matcha mönstret.

6. Sammanfattning

I den här artikeln tittade vi på flyktande tecken i reguljära uttryck i Java.

Vi diskuterade varför regelbundna uttryck måste undvikas och de olika sätten det kan uppnås på.

Som alltid kan källkoden relaterad till den här artikeln hittas på GitHub.