Regulære uttrykk

Innledning

Regulære uttrykk (engelsk: Regular expressions) er tekststrenger som har som oppgave å beskrive et mønster. De gir oss et verktøy for å definere samlinger (mengder) av tekststrenger, slik at en tekststreng tilhører samlingen dersom den har det gitte mønsteret, ellers ikke. Regulære uttrykk kan brukes til å sjekke om en gitt tekststreng har det mønsteret som uttrykket definerer. De kan også brukes på en tekststreng til å erstatte med en annen tekststreng alle delstrenger som har det gitte mønsteret. Og de kan brukes til å splitte en tekststreng i enkeltkomponenter som er atskilt av det gitte mønsteret. (Se notatet Splitte opp tekst i enkeltkomponenter.) I dette notatet skal vi ta for oss reglene for å bygge opp regulære uttrykk, samt beskrive noen forhåndsdefinerte mønstre.

Innledende eksempler: Sammenlikning av tekststrenger

Fra String-klassen kjenner vi metoden equals for å sjekke om to strenger har samme innhold. I String-klassen finner vi imidlertid også metoden matches med følgende beskrivelse:

  public boolean matches(String regex)

Tells whether or not this string matches the given regular expression. An invocation of this method of the form str.matches(regex) yields exactly the same result as the expression

  Pattern.matches(regex, str)
Parameters:
regex - the regular expression to which this string is to be matched
Returns:
true if, and only if, this string matches the given regular expression
Throws:
PatternSyntaxException - if the regular expression's syntax is invalid


Begge instruksjonene

  "Java".matches( "Java" );
  "Java".equals( "Java" );

vil som resultat gi true. Men matches-metoden har større potensiale. Den kan i tillegg til å sjekke om en streng er lik en bestemt annen streng, også sjekke om strengen har et bestemt mønster. For eksempel vil alle følgende tre instruksjoner gi true som resultat:

  "Java er morsomt".matches( "Java.*" );
  "Java er kult".matches( "Java.*" );
  "Java kan brukes til mye".matches( "Java.*" );

I de tre instruksjonene ovenfor er "Java.*" eksempel på et regulært uttrykk. Det beskriver et mønster som begynner med Java og som fortsetter med et vilkårlig antall tegn (eller ingen slike). Delstrengen ".*" vil i dette tilfelle stemme overens med ("matche") en streng bestående av et vilkårlig antall tegn, eller ingen slike (en tom streng).

Metategn

I det regulære uttrykket "Java.*" tolkes punktumet "." som et såkalt metategn, det vil si som et tegn med en spesiell betydning når testen på matching skal foretas. Metategnet "." tolkes som "et hvilket som helst tegn". Stjerna "*" er også et metategn, nærmere bestemt det som kalles en kvantor: den angir et antall. Kvantoren "*" står for antallet "null eller flere".

Følgende metategn kan brukes i forbindelse med matching: ([{\^-$|]})?*+.

I enkelte situasjoner kan det tenkes at vi ikke ønsker at noen av disse tegnene skal tolkes som metategn, men som et vanlig tegn. Det finnes to muligheter for å oppnå dette:

Hvordan definere mønstre

Følgende tabell gir noen eksempler på hvordan mønstre kan defineres i form av delmengder av tegn. I venstre kolonne står det regulære uttrykket, mens det i høyre kolonne er beskrevet hvilke tegn som vil "matche" uttrykket.

Delmengder av tegn
[abc] a, b, eller c
[^abc] Hvilket som helst tegn, unntatt a, b, eller c (negasjon)
[a-zA-Z] a til og med z, eller A til og med Z, (intervall)
[a-d[m-p]] a til og med d, eller m til og med p: [a-dm-p] (union)
[a-z&&[def]] d, e, eller f (snitt)
[a-z&&[^bc]] a til og med z, unntatt b og c: [ad-z] (subtraksjon)
[a-z&&[^m-p]] a til og med z, men ikke m til og med p: [a-lq-z] (subtraksjon)

Forhåndsdefinerte klasser av tegn

Ordet "klasse" har i dette tilfelle ikke noe med java-klasser å gjøre, men betegner en samling eller mengde. Følgende tabell gir en oversikt over de forhåndsdefinerte klassene. Symbolene i venstre kolonne er en forkortelse for den samling som er beskrevet i høyre kolonne.

Forhåndsdefinerte klasser av tegn
. Et hvilket som helst tegn
\d Et siffer: [0-9]
\D Et ikke-siffer: [^0-9]
\s Et "whitespace"-tegn: [ \t\n\x0B\f\r]
\S Et synlig tegn (ikke "whitespace"): [^\s]
\w Et "ord-tegn": [a-zA-Z_0-9]
\W Et "ikke-ord-tegn": [^\w]

Det anbefales å bruke de forhåndsdefinerte klassene av tegn så sant som det er mulig. Det gjør koden mer lesbar og bidrar dessuten til å eliminere feil som kan ha oppstått på grunn av feil konstruksjon av regulære uttrykk.

Uttrykt i ord kan vi summere opp tabellen på følgende måte:

Tilsvarende koder, men med stor bokstav, matcher det motsatte:

Merknad I Java-språket indikerer bakoverskråstrek \ starten på det som kalles en escape-sekvens. Dersom vi ønsker at en slik skråstrek skal inngå som en del av en konkret streng, det som i Java kalles en String-literal, må vi skrive to slike skråstreker etter hverandre. Dette må vi ta hensyn til dersom symbolene i tabellen ovenfor skal inngå i en konkret streng. For eksempel vil strengen "\\d" representere det regulære uttrykket \d.

Kvantorer

I de innledende eksemplene ble stjerne "*" omtalt som en kvantor. Det finnes også en del andre kvantorer. Vi skal bare ta for oss de viktigste av disse. Følgende tabell gir en oversikt.

KvantorBetydning
X?X, én gang, eller ingen
X*X, null eller flere ganger
X+X, én eller flere ganger
X{n}X, nøyaktig n ganger
X{n,}X, minst n ganger
X{n,m}X, minst n ganger, men ikke mer enn m ganger

Merk Kvantorene skal skrives uten bruk av mellomrom (blanke tegn). For eksempel kan X{n,m} ikke skrives som X{n, m} med et mellomrom etter kommaet.

Merknad Det er tillatt å bruke parenteser til å gruppere mønstre. For eksempel vil (ab){3} svare til ababab, mens ab{3} vil svare til abbb.

Eksempler

Eksempel 1
En streng bestående av 11 sifre (for eksempel et kontonummer) kan beskrives slik:

  \\d{11}

Eksempel 2
Et oddetall ender på et av sifrene 1, 3, 5, 7 eller 9 og består av minst ett siffer. Det kan beskrives slik (når det er uten fortegn):

  \\d*[13579]

Eksempel 3
Retningsnummer til Norge (iallfall for mobiltelefoner) blir angitt med +47. Et mobilnummer på 8 sifre og med et slikt retningsnummer foran kan derfor beskrives slik:

  \+47\\d{8}

Copyright © Kjetil Grønning, 2007