Regelmessige uttrykk i Kotlin

1. Introduksjon

Vi kan finne bruk (eller misbruk) av vanlige uttrykk i stort sett alle slags programvare, fra raske skript til utrolig komplekse applikasjoner.

I denne artikkelen ser vi hvordan du bruker vanlige uttrykk i Kotlin.

Vi vil ikke diskutere syntaks for vanlig uttrykk; det er generelt behov for fortrolighet med regulære uttrykk for å følge artikkelen tilstrekkelig, og kunnskap om Java-mønster-syntaksen er spesielt anbefalt.

2. Oppsett

Selv om vanlige uttrykk ikke er en del av Kotlin-språket, kommer de med standardbiblioteket.

Vi har sannsynligvis allerede det som en avhengighet av prosjektet vårt:

 org.jetbrains.kotlin kotlin-stdlib 1.2.21 

Vi finner den nyeste versjonen av kotlin-stdlib på Maven Central.

3. Lage et objekt for regulært uttrykk

Regulære uttrykk er forekomster av kotlin.text.Regex klasse. Vi kan lage en på flere måter.

En mulighet er å ringe Regex konstruktør:

Regex ("a [bc] + d?")

eller vi kan ringe toRegex metode på en Streng:

"a [bc] + d?". toRegex ()

Til slutt kan vi bruke en statisk fabrikkmetode:

Regex.fromLiteral ("a [bc] + d?")

Bortsett fra en forskjell som er forklart i neste avsnitt, er disse alternativene ekvivalente og tilsvarer personlig preferanse. Bare husk å være konsekvent!

Tips: Vanlige uttrykk inneholder ofte tegn som vil bli tolket som rømningssekvenser i String bokstavelige. Vi kan dermed bruke rå Strenger å glemme flere nivåer av å rømme:

"" "a [bc] + d? \ W" "". toRegex ()

3.1. Matchende alternativer

Begge Regex konstruktør og toRegex metode tillater oss å spesifisere et ekstra tilleggsalternativ eller et sett:

Regex ("a (b | c) + d?", CANON_EQ) Regex ("a (b | c) + d?", SetOf (DOT_MATCHES_ALL, KOMMENTARER)) "a (b | c) + d?". ToRegex (MULTILINE) "a (b | c) + d?". ToRegex (setOf (IGNORE_CASE, COMMENTS, UNIX_LINES))

Alternativer er oppført i RegexOption klasse, som vi enkelt importerte statisk i eksemplet ovenfor:

  • IGNORE_CASE - muliggjør små og store bokstaver
  • MULTILINE - endrer betydningen av ^ og $ (se Mønster)
  • BOKSTAVELIG - forårsaker at metategn eller rømningssekvenser i mønsteret ikke får noen spesiell betydning
  • UNIX_LINES - i denne modusen, bare \ n er anerkjent som en linjeterminator
  • KOMMENTARER - tillater mellomrom og kommentarer i mønsteret
  • DOT_MATCHES_ALL - får punktet til å matche hvilket som helst tegn, inkludert en linjeterminator
  • CANON_EQ - muliggjør ekvivalens ved kanonisk nedbrytning (se Mønster)

4. Matching

Vi bruker vanlige uttrykk først og fremst for å matche input Strenger, og noen ganger for å trekke ut eller erstatte deler av dem.

Vi vil nå se i detalj på metodene som tilbys av Kotlin's Regex klasse for matching Strenger.

4.1. Kontrollerer delvis eller totalt samsvar

I disse brukssakene er vi interessert i å vite om en String eller en del av en String tilfredsstiller vårt vanlige uttrykk.

Hvis vi bare trenger en delvis kamp, ​​kan vi bruke inneholderMatchIn:

val regex = "" "a ([bc] +) d?" "". toRegex () assertTrue (regex.containsMatchIn ("xabcdy"))

Hvis vi vil ha helheten String for å matche i stedet, bruker vi fyrstikker:

assertTrue (regex.matches ("abcd"))

Merk at vi kan bruke fyrstikker som en infix-operatør også:

assertFalse (regex samsvarer med "xabcdy")

4.2. Pakke ut samsvarende komponenter

I disse brukssakene ønsker vi å matche en String mot et vanlig uttrykk og trekk ut deler av String.

Vi vil kanskje matche hele Streng:

val matchResult = regex.matchEntire ("abbccbbd")

Eller kanskje vi vil finne den første understrengen som passer:

val matchResult = regex.find ("abcbabbd")

Eller kanskje for å finne alle matchende underlag på en gang, som en Sett:

val matchResults = regex.findAll ("abcb abbd")

I begge tilfeller, hvis kampen er vellykket, blir resultatet en eller flere forekomster av MatchResult klasse. I neste avsnitt vil vi se hvordan du bruker den.

Hvis kampen ikke lykkes, returnerer disse metodene i stedet null eller det tomme Sett i tilfelle finn alle.

4.3. De MatchResult Klasse

Forekomster av MatchResult klasse representerer vellykkede kamper av noen inputstrenger mot et vanlig uttrykk; enten komplette eller delvise kamper (se forrige avsnitt).

Som sådan har de en verdi, som er matchet String eller substring:

val regex = "" "a ([bc] +) d?" "". toRegex () val matchResult = regex.find ("abcb abbd") assertEquals ("abcb", matchResult.value)

Og de har en område av indekser for å indikere hvilken del av inngangen som ble matchet:

assertEquals (IntRange (0, 3), matchResult.range)

4.4. Grupper og destruksjon

Vi kan også trekke ut grupper (matchede understrenger) fra MatchResult tilfeller.

Vi kan skaffe dem som Strenger:

assertEquals (listOf ("abcb", "bcb"), matchResult.groupValues)

Eller vi kan også se dem som MatchGroup gjenstander som består av en verdi og en område:

assertEquals (IntRange (1, 3), matchResult.groups [1] .range)

Gruppen med indeks 0 er alltid hele matchet String. Indekser større enn 0 representerer i stedet grupper i det regulære uttrykket, avgrenset av parentes, for eksempel ([bc] +) i vårt eksempel.

Vi kan også ødelegge MatchResult forekomster i en oppgaveuttalelse:

val regex = "" "([\ w \ s] +) er (\ d +) år gammel" "". toRegex () val matchResult = regex.find ("Mikke Mus er 95 år") val (navn, alder ) = matchResult !!. destruert assertEquals ("Mickey Mouse", navn) assertEquals ("95", alder)

4.5. Flere kamper

MatchResult har også en neste metoden som vi kan bruke for å oppnå neste kamp av inngangen String mot det vanlige uttrykket, hvis det er noen:

val regex = "" "a ([bc] +) d?" "". toRegex () var matchResult = regex.find ("abcb abbd") assertEquals ("abcb", matchResult !!. verdi) matchResult = matchResult. neste () assertEquals ("abbd", matchResult !!. verdi) matchResult = matchResult.next () assertNull (matchResult)

Som vi kan se, neste returnerer null når det ikke er flere kamper.

5. Skifte ut

En annen vanlig bruk av regulære uttrykk er erstatte matchende underlag med andre Strenger.

For dette formålet har vi to metoder som er lett tilgjengelige i standardbiblioteket.

En, erstatte, er for å erstatte alle forekomster av en matching Streng:

val regex = "" "(rød | grønn | blå)" "". toRegex () val vakker = "Roser er røde, fioler er blå" val grim = regex.replace (vakker, "mørk") påstandEquals ("Roses are mørke, fiolene er mørke ", dystre)

Den andre, erstatte første, er for å erstatte bare den første forekomsten:

val skinnende = regex.replaceFirst (vakker, "regnbue") hevderEquals ("Roser er regnbue, fioler er blå", skinnende)

5.1. Komplekse erstatninger

Til mer avanserte scenarier, når vi ikke vil erstatte fyrstikker med konstant Strenger, men vi vil å bruke en transformasjon i stedet, Regex gir oss fremdeles det vi trenger.

Skriv inn erstatte overbelastning ved å stenge:

val reallyBeautiful = regex.replace (vakker) {m -> m.value.toUpperCase () + "!" } assertEquals ("Roses are RED !, Fiolets are BLUE!", reallyBeautiful)

Som vi kan se, kan vi beregne en erstatning for hver kamp String bruker den kampen.

6. Splitting

Til slutt vil vi kanskje å dele en String inn i en liste over understreng i henhold til et vanlig uttrykk. Igjen, Kotlin's Regex har fått oss dekket:

val regex = "" "\ W +" "". toRegex () val beautiful = "Roser er røde, fioler er blå" assertEquals (listOf ("Roser", "er", "røde", "Fioler", "er" , "blå"), regex.split (vakker))

Her samsvarer det regulære uttrykket med et eller flere tegn som ikke er ord, så resultatet av delingsoperasjonen er en liste over ord.

Vi kan også sette en begrensning på lengden på den resulterende listen:

assertEquals (listOf ("Roses", "are", "red", "Fiolets are blue"), regex.split (vakker, 4))

7. Java-interoperabilitet

Hvis vi trenger å overføre vårt vanlige uttrykk til Java-kode eller et annet API for JVM-språk som forventer en forekomst av java.util.regex.Mønster, kan vi ganske enkelt konvertere våre Regex:

regex.toPattern ()

8. Konklusjoner

I denne artikkelen har vi undersøkt støtte for vanlig uttrykk i Kotlin-standardbiblioteket.

For ytterligere informasjon, se Kotlin-referansen.

Implementeringen av alle disse eksemplene og kodebitene finnes i GitHub-prosjektet - dette er et Maven-prosjekt, så det skal være enkelt å importere og kjøre som det er.


$config[zx-auto] not found$config[zx-overlay] not found