Reguliere expressies in Kotlin

1. Inleiding

We kunnen gebruik (of misbruik) van reguliere expressies vinden in vrijwel elke soort software, van snelle scripts tot ongelooflijk complexe applicaties.

In dit artikel zullen we zien hoe u reguliere expressies in Kotlin kunt gebruiken.

We zullen de syntaxis van reguliere expressies niet bespreken; bekendheid met reguliere expressies is in het algemeen vereist om het artikel adequaat te volgen, en kennis van de Java Pattern-syntaxis wordt in het bijzonder aanbevolen.

2. Installatie

Hoewel reguliere expressies geen deel uitmaken van de Kotlin-taal, worden ze wel geleverd met de standaardbibliotheek.

We hebben het waarschijnlijk al als een afhankelijkheid van ons project:

 org.jetbrains.kotlin kotlin-stdlib 1.2.21 

We kunnen de nieuwste versie van kotlin-stdlib vinden op Maven Central.

3. Een object voor reguliere expressies maken

Reguliere expressies zijn voorbeelden van de kotlin.text.Regex klasse. We kunnen er op verschillende manieren een maken.

Een mogelijkheid is om het Regex constructeur:

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

of we kunnen de toRegex methode op een Draad:

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

Ten slotte kunnen we een statische fabrieksmethode gebruiken:

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

Behalve een verschil dat in de volgende sectie wordt uitgelegd, zijn deze opties equivalent en komen ze overeen met persoonlijke voorkeur. Onthoud gewoon om consistent te zijn!

Tip: reguliere expressies bevatten vaak tekens die zouden worden geïnterpreteerd als escape-reeksen in Draad letterlijke. We kunnen dus rauw gebruiken Snaren om meerdere ontsnappingsniveaus te vergeten:

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

3.1. Bijpassende opties

Beide Regex constructor en het toRegex methode stellen ons in staat om een ​​enkele extra optie of een set te specificeren:

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

De opties worden opgesomd in het RegexOption class, die we gemakkelijk statisch hebben geïmporteerd in het bovenstaande voorbeeld:

  • NEGEER ZAAK - maakt hoofdletterongevoelige matching mogelijk
  • MULTILINE - verandert de betekenis van ^ en $ (zien Patroon)
  • LITERAAL - zorgt ervoor dat metatekens of escape-reeksen in het patroon geen speciale betekenis krijgen
  • UNIX_LINES - in deze modus zijn alleen de \ n wordt herkend als een lijnafsluiter
  • OPMERKINGEN - staat witruimte en opmerkingen in het patroon toe
  • DOT_MATCHES_ALL - zorgt ervoor dat de punt overeenkomt met een willekeurig teken, inclusief een regelafsluiter
  • CANON_EQ - maakt gelijkwaardigheid mogelijk door canonieke ontbinding (zie Patroon)

4. Bijpassende

We gebruiken voornamelijk reguliere expressies om de invoer te matchen Snaren, en soms om er onderdelen uit te halen of te vervangen.

We zullen nu in detail kijken naar de methoden die door Kotlin's worden aangeboden Regex klasse voor matching Snaren.

4.1. Gedeeltelijke of totale overeenkomsten controleren

In deze gebruikssituaties zijn we geïnteresseerd in weten of a Draad of een deel van een Draad voldoet aan onze reguliere expressie.

Als we slechts een gedeeltelijke match nodig hebben, kunnen we gebruiken bevatMatchIn:

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

Als we het geheel willen Draad om in plaats daarvan te matchen, gebruiken we wedstrijden:

assertTrue (regex.matches ("abcd"))

Merk op dat we kunnen gebruiken wedstrijden ook als tussenvoegseloperator:

assertFalse (regex komt overeen met "xabcdy")

4.2. Overeenkomende componenten extraheren

In deze use-cases willen we passend bij een Draad tegen een reguliere expressie en extraheer delen van de Draad.

Misschien willen we het geheel matchen Draad:

val matchResult = regex.matchEntire ("abbccbbd")

Of we willen misschien de eerste deelstring vinden die overeenkomt:

val matchResult = regex.find ("abcbabbd")

Of misschien om alle bijpassende substrings tegelijk te vinden, als een Set:

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

In beide gevallen, als de match succesvol is, is het resultaat een of meer exemplaren van de MatchResult klasse. In de volgende sectie zullen we zien hoe u deze kunt gebruiken.

Als de overeenkomst niet succesvol is, keren deze methoden terug nul of de lege Set in het geval van vind alle.

4.3. De MatchResult Klasse

Instanties van de MatchResult class staat voor succesvolle overeenkomsten van een invoertekenreeks met een reguliere expressie; ofwel volledige of gedeeltelijke overeenkomsten (zie de vorige sectie).

Als zodanig hebben ze een waarde, dat is de matched Draad of substring:

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

En ze hebben een bereik van indices om aan te geven welk deel van de invoer overeenkomt:

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

4.4. Groepen en vernietiging

We kunnen ook groepen (gematchte substrings) extraheren MatchResult gevallen.

We kunnen ze verkrijgen als Snaren:

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

Of we kunnen ze ook bekijken als MatchGroup objecten bestaande uit a waarde en een bereik:

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

De groep met index 0 is altijd de volledige match Draad. Indices groter dan 0 vertegenwoordigen in plaats daarvan groepen in de reguliere expressie, gescheiden door haakjes, zoals ([bc] +) in ons voorbeeld.

We kunnen ook vernietigen MatchResult instanties in een opdrachtverklaring:

val regex = "" "([\ w \ s] +) is (\ d +) jaar oud" "". toRegex () val matchResult = regex.find ("Mickey Mouse is 95 jaar oud") val (naam, leeftijd ) = matchResult !!. destructured assertEquals ("Mickey Mouse", naam) assertEquals ("95", leeftijd)

4.5. Meerdere wedstrijden

MatchResult heeft ook een De volgende methode die we kunnen gebruiken om de volgende overeenkomst van de invoer te verkrijgen Draad tegen de reguliere expressie, als er iets is:

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

Zoals we kunnen zien, De volgende geeft null terug als er geen overeenkomsten meer zijn.

5. Vervangen

Een ander veelgebruikt gebruik van reguliere expressies is bijpassende substrings vervangen door andere Snaren.

Voor dit doel hebben we twee methoden direct beschikbaar in de standaardbibliotheek.

Een, vervangen, is voor het vervangen van alle exemplaren van een overeenkomst Draad:

val regex = "" "(rood | groen | blauw)" "". toRegex () val beautiful = "Rozen zijn rood, viooltjes zijn blauw" val grim = regex.replace (mooi, "donker") assertEquals ("Rozen zijn donker, viooltjes zijn donker ", grimmig)

De andere, vervangenFirst, is alleen voor het vervangen van het eerste exemplaar:

val shiny = regex.replaceFirst (mooi, "regenboog") assertEquals ("Rozen zijn regenboog, viooltjes zijn blauw", glanzend)

5.1. Complexe vervangingen

Voor meer geavanceerde scenario's, als we overeenkomsten niet willen vervangen door constant Snaren, maar we willen om een ​​transformatie toe te passen in plaats daarvan, Regex geeft ons nog steeds wat we nodig hebben.

Voer het vervangen overbelasting bij sluiting:

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

Zoals we kunnen zien, kunnen we voor elke match een vervanging berekenen Draad met behulp van die wedstrijd.

6. Splitsen

Eindelijk willen we misschien om een Draad in een lijst met subtekenreeksen volgens een reguliere expressie. Nogmaals, Kotlin's Regex heeft ons gedekt:

val regex = "" "\ W +" "". toRegex () val beautiful = "Rozen zijn rood, viooltjes zijn blauw" assertEquals (listOf ("Roses", "are", "red", "Violets", "are" , "blauw"), regex.split (mooi))

Hier komt de reguliere expressie overeen met een of meer niet-woordtekens, dus het resultaat van de splitsing is een lijst met woorden.

We kunnen ook een limiet stellen aan de lengte van de resulterende lijst:

assertEquals (listOf ("Roses", "are", "red", "Violets are blue"), regex.split (mooi, 4))

7. Java-interoperabiliteit

Als we onze reguliere expressie moeten doorgeven aan Java-code of een andere JVM-taal-API die een exemplaar van java.util.regex.Pattern, we kunnen eenvoudig onze Regex:

regex.toPattern ()

8. Conclusies

In dit artikel hebben we de ondersteuning voor reguliere expressies in de Kotlin-standaardbibliotheek onderzocht.

Zie de Kotlin-referentie voor meer informatie.

De implementatie van al deze voorbeelden en codefragmenten is te vinden in het GitHub-project - dit is een Maven-project, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.


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