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:
- sette en bakoverskråstrek \ foran metategnet (som i eksemplet
\.
), eller
- sette tegnet eller tegnene mellom \Q (Q for "quote") og \E
(E for "end") (som i eksemplet
\Q.\E
).
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:
\d
matcher alle sifre
\s
matcher blanktegn, tabulatortegn og linjeskifttegn
\w
matcher tegn brukt i ord: store og små bokstaver, sifre
og lav bindestrek
Tilsvarende koder, men med stor bokstav, matcher det motsatte:
\D
matcher ikke-sifre
\S
matcher ikke-blanktegn
\W
matcher tegn som ikke inngår i ord
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.
Kvantor | Betydning |
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