Innholdsoversikt for programutvikling
String
String
-metoderString
Fra før vet vi at vi bruker datatypen String
for variable
som skal inneholde tekst. Vi skal nå gjøre oss kjent med noen av metodene i
String
-klassen og se eksempler på hvordan de kan brukes til å
undersøke og manipulere tekst.
Vi vet at vi kan opprette String
-objekter i form av
String
-literaler som i følgende eksempel:
String navn = "Snorre Sturlason";
Vi kan imidlertid også opprette String
-objekter på vanlig måte ved
bruk av new
-operatoren og en konstruktør.
I String
-klassen er det
definert mange forskjellige konstruktører. De mest aktuelle er følgende:
public String()
""
.public String(String kilde)
kilde
public String(char[] kilde)
kilde
inneholder.public String(char[] kilde, int startpos, int antall)
kilde
inneholder. Parameteren startpos
angir indeksposisjonen som første tegn
skal hentes fra i kildearrayen, mens parameteren antall
angir hvor
mange tegn som skal hentes.Instruksjonen
String abc = "abc";
er likeverdig med instruksjonene
char data[] = {'a', 'b', 'c'}; String abc = new String(data);
String
-objekter er indeksert fra 0 og oppover,
på tilsvarende måte som array-objekter. Enkelttegnene i en tekst
er av type char
, som er en av de såkalte primitive (grunnleggende) datatypene i
Java-språket. For å hente ut de enkelte tegnene kan vi bruke String
-metoden
charAt
:
String s = ...; int indeks = ...; char tegn = s.charAt(indeks);
Som det er tilfelle for array-objekter, kjenner også String
-objekter sin egen lengde (antall tegn):
int lengde = s.length();
Legg merke til at for String
-objekter er length
en metode,
mens det for arrayer er et datafelt:
int[] array = ...; int arraylengde = array.length;
Dersom vi i en String
-metode bruker en indeksposisjon som er mindre enn null
eller større enn length() - 1
, så vil det bli kastet ut en
IndexOutOfBoundsException
.
Et tegn, verdi av type char
, er i Java kodet etter systemet Unicode,
som bruker 2 byter (16 biter) for hvert tegn.
Følgende opplisting gir en kort oversikt over de viktigste String
-metodene
og deres virkemåte. Fullstendig oversikt kan du finne ved å klikke på linken
String.
Oversikten inneholder også noen metoder som kan brukes til å undersøke tegn.
Disse finnes i klassen
Character.
Navnene på metodene er stort sett selvforklarende.
String
-metoder og hva de returnererString s1 = "Eksempel"; String s2 = "eksempel"; INSTRUKSJON RETUR s1.charAt(2); 's' s1.substring(3); "empel" s1.substring(3, 6); "emp" s1.length(); 8 s1.indexOf('e'); 3 //første forekomst s1.lastIndexOf('e'); 6 //siste forekomst s2.indexOf('e', 2); 3 //starter søket i indeksposisjon 2 s1.indexOf("sem"); 2 s1.indexOf("mep"); -1 //finnes ikke s1.startsWith("eks"); false s1.endsWith("pel"); true s1.toLowerCase(); "eksempel" //s1 er uendret! s1.toUpperCase(); "EKSEMPEL" //s1 er uendret! s1.equals(s2); false s1.equalsIgnoreCase(s2); true s1.compareTo(s2); negativt heltall s2.compareTo(s1); positivt heltall s1.compareToIgnoreCase(s2); 0 s1.replace('e', 'E'); "EksEmpEl" //s1 er uendret!
Annen nyttig String
-metode:
trim() Returnerer en streng der eventuelle blanke tegn foran og bak i strengen er fjernet.
static
-metoder i klassen Character
Eksempel
char t = ...; //gi verdi til t if (Character.isDigit(t)) ... if (Character.isLetter(t)) ... if (Character.isLetterOrDigit(t)) ... if (Character.isLowerCase(t)) ... if (Character.isUpperCase(t)) ... if (Character.isSpaceChar(t)) ... if (Character.isWhiteSpace(t)) ... char s = Character.toUpperCase(t); char c = Character.toLowerCase(s);
Konvertere tegn til tilsvarende String
:
String s = (new Character(t)).toString(); //toString er ikke static
Merk deg at String
-objekter er såkalt immutable: når de først
er opprettet, så kan de ikke endres. String
-metodene for omforming av
String
-objekter returnerer derfor et nytt String
-objekt
med den ønskete omformingen. Dersom en streng skal bygges opp av mange småbiter, vil det
være ineffektivt å opprette et stort antall String
-objekter som ikke har annen
oppgave enn å være et ledd i en oppbyggingsprosess. I slike tilfelle kunne vi under byggeprosessen ønske oss en
type dynamisk streng. Det har vi i klassen StringBuilder
som er beskrevet i neste avsnitt.
Når vi skal bygge opp en streng av mange småbiter, vil det istedenfor å skjøte sammen
bitene ved hjelp av +
-operatoren være mer effektivt å bygge opp et
StringBuilder
-objekt
som vi så konverterer til String
til slutt.
Objektet kan vi opprette som et i utgangspunktet tomt objekt på følgende måte:
StringBuilder bygger = new StringBuilder();
Alternativt kan vi supplere konstruktøren med en String
-parameter som gir en
startstreng som utgangspunkt. Videre kan vi skjøte til enten enkelttegn (av type
char
) eller strenger:
bygger.append(tegn); bygger.append(streng);
Det finnes også mange andre varianter av append
-metoden for tilføyelse av forskjellig
type data. Dessuten er det mange muligheter for å legge inn data innimellom det som allerede eksisterer
ved å bruke de forskjellige variantene til insert
-metoden. Når vi er ferdige med å
bygge opp StringBuilder
-objektet, kan vi få hentet ut en streng som inneholder de data
vi har lagt inn:
String ferdigstreng = bygger.toString();
I oversikten ovenfor er det fire metoder som har med sammenlikning av strenger å gjøre:
equals, equalsIgnoreCase, compareTo
og compareToIgnoreCase
. De to
første sammenlikner innholdet i String
-objektene de brukes på. Metoden equals
returnerer true
bare i tilfelle strengene
inneholder nøyaktig de samme tegnene i samme
rekkefølge, det vil si dersom tegnene har de samme Unicode-kodene. I metoden
equalsIgnoreCase
gjøres det ikke noe skille mellom små og store bokstaver.
For eksempel vil Ë
og ë
bli regnet som like, men forskjellige fra
E
og e
. Andre tegn enn bokstaver, for eksempel skilletegn, blir
bare regnet for å være lik seg selv.
Metodene compareTo
og compareToIgnoreCase
har med rekkefølge å gjøre,
nærmere bestemt det som kalles leksikografisk rekkefølge.
Det som sammenliknes, er tegnenes Unicode-verdier. Leksikografisk rekkefølge er definert på denne måten:
Dersom to strenger er forskjellige, så har de enten forskjellige tegn i en indeksposisjon som er
gyldig for begge strengene, eller så har de forskjellig lengde, eller begge deler. Dersom de har forskjellige
tegn i én eller flere indeksposisjoner, så la k være den minste av disse indeksposisjonene.
Da vil den strengen som har det minste tegnet i indeksposisjon k, bestemt ved å bruke
sammenlikningsoperatoren < på tegnenes Unicode-verdier, være den strengen som kommer først i
leksikografisk rekkefølge. I dette tilfelle vil instruksjonen
streng1.compareTo( streng2 )
returnere verdien
streng1.charAt(k) - streng2.charAt(k)
Dersom strengene ikke er forskjellige i noen av indeksposisjonene som er gyldige for begge,
vil den korteste strengen være den som kommer først i leksikografisk rekkefølge. I dette tilfelle
vil compareTo
returnere lengdeforskjellen mellom strengene, det vil si verdien
streng1.length() - streng2.length()
Som navnet indikerer, vil compareToIgnoreCase
ikke skille mellom store og små
bokstaver, tilsvarende som for equalsIgnoreCase
.
Merk at metodene compareTo
og compareToIgnoreCase
ikke tar noen
hensyn til nasjonale særegenheter. For eksempel vil metodene ikke behandle riktig rekkefølgen for
de norske bokstavene Æ, Ø og Å, samt de små variantene av disse. Metoden compareTo
vil dessuten regne alle store bokstaver for å komme foran alle små, slik at for eksempel
Z regnes å komme foran a. Hvordan vi skal få foretatt riktig sortering av strenger, slik at
det også tas hensyn til disse tingene, er beskrevet i notatet
Sortering av strenger.
Merk for øvrig at sammenlikningsoperatoren ==
brukt på
String
-objekter sammenlikner objektenes peker-verdier (referanser). Med andre ord så
sjekkes det om det blir referert til det samme objektet. Som regel er det ikke dette vi er interessert i
å sjekke, men om to forskjellige objekter har samme innhold. For å sjekke dette er det equals
eller
equalsIgnoreCase
vi må bruke. Merk ellers at
streng1.equals(streng2)
alltid vil ha samme verdi som
streng1.compareTo(streng2) == 0
Det samme er tilfelle med
streng1.equalsIgnoreCase(streng2)
og
streng1.compareToIgnoreCase(streng2) == 0
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 avsnittet Splitte opp tekst i enkeltkomponenter lenger ute.) Her skal vi ta for oss reglene for å bygge opp regulære uttrykk, samt beskrive noen forhåndsdefinerte mønstre.
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).
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:
\.
), eller\Q.\E
).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)
Ordet "klasse" har i dette tilfelle ikke noe med javaklasser å 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 blir anbefalt å 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 bindestrekTilsvarende koder, men med stor bokstav, matcher det motsatte:
\D
matcher ikke-sifre\S
matcher ikke-blanktegn\W
matcher tegn som ikke inngår i ordMerknad 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
String
-literal. For eksempel vil strengen "\\d"
representere
det regulære uttrykket \d
.
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 ingenX*
X
, null eller flere gangerX+
X
, én eller flere gangerX{n}
X
, nøyaktign
gangerX{n,}
X
, minstn
gangerX{n,m}
X
, minstn
ganger, men ikke mer ennm
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
.
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}"
Som verktøy for å splitte opp strenger i enkeltkomponenter, blir det for
ny kode anbefalt å bruke String
-klassens split
-metode
eller noen av verktøyene i pakken
java.util.regex.
Det er også mulig å bruke en
Scanner
til slik oppsplitting. En Scanner
kan som kilde for det som skal
splittes opp også bruke en hvilken som helst input-strøm, for
eksempel en fil. Dessuten kan den gjenkjenne forskjellige datatyper.
Tidligere var det objekter av klassen StringTokenizer
som ble
brukt til å foreta oppsplitting av tekst i enkeltkomponenter. Av hensyn til
kompatibilitet bakover finnes klassen fortsatt, men anbefales ikke brukt i ny kode.
Bruk av StringTokenizer
-objekter er beskrevet i notatet
Lese tekst ord for ord ved hjelp av en StringTokenizer
.
For å definere skille mellom enkeltkomponentene i den teksten som skal
splittes opp, bruker vi et regulært uttrykk. (For en
StringTokenizer
blir det bare brukt en streng.) Hva som menes med
regulære uttrykk er beskrevet i avsnittet
Regulære uttrykk ovenfor.
String
-klassens split
-metodeMetoden finnes i to versjoner. Som regel er det den som har bare én parameter vi har bruk for:
public String[] split(String regex)
Parameteren regex
er det regulære uttrykket som definerer
skillet mellom enkeltkomponentene. Metoden returnerer en array som inneholder de enkelte
komponentene som oppsplittingen har gitt. Arrayen kan være av vilkårlig størrelse.
Merk deg imidlertid at oppsplittingen kan inneholde komponenter som består av
tomme strenger. Men eventuelle tomme strenger på slutten vil ikke bli tatt med.
Dersom den strengen
som skal splittes opp ikke har noen delstreng som passer med det regulære
uttrykket, vil den returnerte arrayen ha ett element og dette inneholder den
strengen som skulle splittes opp. Metoden har samme virkning som å bruke den
andre versjonen av metoden (se nedenfor) med grense-parameter lik null.
Eksempel 1
String test = "Dette er en test på bruk av split-metoden."; String[] resultat = test.split("\\s"); for (int i = 0; i < resultat.length; i++) System.out.println(resultat[i]);
vil gi følgende utskrift:
Dette er en test på bruk av split-metoden.
Husk at det regulære uttrykket \s
betyr såkalt
whitespace. Siden uttrykket inngår i en streng når det blir brukt
i metodekallet ovenfor, må det være en ekstra bakoverskråstrek foran. (Se avsnittet
om regulære uttrykk.) Bindestreken og punktumet i den siste komponenten som
ble skrevet ut, er ikke whitespace. Derfor får vi det ut på denne måten.
Eksempel 2
Strengen "20:00:00"
resulterer i følgende oppsplitting med de
regulære uttrykkene som er angitt i tabellens første kolonne:
Regulært uttrykk | Resultat |
---|---|
: | {"20", "00", "00"} |
0 | {"2", ":", "", ":"} |
Legg merke til at vi i det siste tilfelle får en tom streng innimellom, men at den tomme strengen på slutten ikke blir tatt med i returen.
Den andre versjonen av split
-metoden har to parametre:
public String[] split(String regex, int grense)
Første parameter har samme betydning som i første versjon av metoden.
Parameteren grense
kontrollerer antall ganger det regulære uttrykket
skal brukes. Parameteren vil derfor påvirke størrelsen på den returnerte arrayen.
Dersom grensen n er større enn null, vil det regulære uttrykket bli
brukt høyst n - 1 ganger. Den returnerte arrayen kan dermed ikke få
mer enn n plasser. Siste element i arrayen vil da inneholde all tekst
i kildestrengen som følger etter siste match til det regulære uttrykket.
Dersom n er null eller negativ, vil det regulære uttrykket bli brukt
så mange ganger som mulig og den returnerte arrayen kan ha hvilken som helst
lengde. Det samme er tilfelle når n er null, men eventuelle tomme
strenger på slutten vil da bli droppet.
Eksempler
Følgende eksempler viser hvordan forskjellige verdier for grenseparameteren
påvirker oppsplittingen av strengen "20:00:00"
med de
regulære uttrykk som er angitt i tabellens første kolonne.
Regulært uttrykk | Grense | Resultat |
---|---|---|
: | 2 | {"20", "00:00"} |
: | 5 | {"20", "00", "00"} |
: | -2 | {"20", "00", "00"} |
0 | 5 | {"2", ":", "", ":", ""} |
0 | -2 | {"2", ":", "", ":", ""} |
0 | 0 | {"2", ":", "", ":"} |
Legg merke til når den returnerte arrayen inneholder tomme strenger på slutten, og når den ikke gjør det.
Scanner
En Scanner
kan brukes til å splitte opp tekstlig input i
enkeltkomponenter. Som input kan det brukes en streng eller en strøm, for
eksempel en fil eller input fra tastaturet. Byte fra inputstrømmen blir
konvertert til tegn. Det kan enten være i samsvar med default-tegnsettet til
den underliggende plattform (noe som er unødvendig å spesifisere), eller i
samsvar med et spesifisert tegnsett. I tillegg til å splitte opp i strengkomponenter
har en Scanner
evne til å gjenkjenne verdier av javas primitive
datatyper (gitt på strengform), unntatt typen
char
, slik at den
kan returnere neste verdi av en spesifisert type. Også typene
BigInteger
og BigDecimal
kan den gjenkjenne og
returnere. I numeriske verdier blir det påstått at det også kan være
tusen-separator i samsvar med den formateringsstandard som gjelder på stedet
(eller på en spesifisert lokalitet). I Norge
er det mellomrom (blankt tegn) som er den korrekte tusen-separatoren. Strengen
"32 767" skulle derfor på korrekt måte bli lest som
int
-verdien
32767
. Det viser seg imidlertid at dette ikke stemmer. Strengen vil
bli tolket som to separate heltallsverdier. Derimot blir komma på riktig måte
tolket som desimaltegn i en streng som "8,5"
.
Dersom annet ikke er spesifisert, er det såkalt whitespace som vil bli brukt som
skille mellom komponentene når oppsplittingen foretas. Men det er mulig ved hjelp av
metoden useDelimiter
å spesifisere hvilket som helst
regulært uttrykk som skille mellom komponentene. Ønsker vi seinere å gå tilbake
til default-virkemåten med bruk av whitespace som skille, kan vi oppnå det ved
kall på metoden reset
.
Når vi er ferdig med å bruke en Scanner
, er det nødvendig å
lukke den ved kall på dens close
-metode for å signalisere at vi
er ferdig med å bruke dens eventuelle underliggende strøm. Denne vil da også
automatisk bli lukket.
Eksempel 1
I programmet
Forfatternavn.java
som er gjengitt nedenfor, blir det fra tekstfeltet input
lest inn navn på formatet
Etternavn, Fornavn (eventuelt et eller flere mellomnavn).
Navnene skrives ut igjen i tekstfeltet output
på formatet
Fornavn (eventuelt et eller flere mellomnavn) Etternavn.
Eksempel: Innlest navn
Beauvoir, Simone de
blir skrevet ut igjen som
Simone de Beauvoir
I programmet er navnene kalt forfatternavn, men det kan selvsagt være hvilke
som helst andre navn på samme format. Driverklasse for programmet finnes i
fila
Tokentest.java
Innlesing, konvertering og utskrift av navn skjer i metoden
konverterNavn
. Den splitter opp det innleste navnet ved hjelp
av en Scanner
der komma og mellomrom oppfattes som skille
mellom ordene. Først trekkes etternavnet ut av den innleste strengen og lagres
i en egen variabel. Deretter trekkes det ut fornavn og eventuelle mellomnavn
så lenge det finnes flere. De tilføyes etter tur i en egen variabel for
fornavn og mellomnavn. Til slutt blir strengen som inneholder etternavnet
tilføyd, og det hele vises i tekstfeltet for utskrift. For øvrig blir det
mellom de enkelte navnene lagt inn mellomrom.
1 import javax.swing.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.util.*; 5 6 public class Forfatternavn extends JFrame 7 { 8 private JTextField input, output; 9 10 public Forfatternavn() 11 { 12 super( "Forfatternavn" ); 13 input = new JTextField( 30 ); 14 output = new JTextField( 30 ); 15 output.setEditable( false ); 16 Container c = getContentPane(); 17 c.setLayout( new FlowLayout() ); 18 c.add( new JLabel( "Forfatternavn (ettenavn, fornavn):" ) ); 19 c.add( input ); 20 c.add( new JLabel( "Forfatternavn (fornavn etternavn):" ) ); 21 c.add( output ); 22 input.addActionListener( new Inputlytter() ); 23 setSize( 600, 100 ); 24 setVisible( true ); 25 } 26 27 public void konverterNavn() 28 { 29 String navn = input.getText(); 30 Scanner leser = new Scanner( navn ); 31 leser.useDelimiter("[,\\s]+"); 32 String etternavn = ""; 33 if ( leser.hasNext() ) 34 etternavn = leser.next(); 35 String fornavn = ""; 36 while ( leser.hasNext() ) 37 fornavn += leser.next() + " "; 38 39 leser.close(); 40 41 if ( !etternavn.equals( "" ) ) 42 output.setText( fornavn + etternavn ); 43 else 44 output.setText( "Ingen navn lest inn." ); 45 } 46 47 private class Inputlytter implements ActionListener 48 { 49 public void actionPerformed( ActionEvent e ) 50 { 51 if ( e.getSource() == input ) 52 konverterNavn(); 53 } 54 } 55 }
Merknad I eksemplet ovenfor brukes strengen
"[,\\s]+"
som det regulære uttrykket som definerer skille
mellom komponentene. Det betyr at skille er enten minst et blankt tegn (egentlig
minst et såkalt whitespace), eller minst et komma, eventuelt etterfulgt av et antall
blanke.
Bildet under viser vinduet fra en kjøring av programmet.
Eksempel 2
Programmet
ScanSum
som er gjengitt
nedenfor er hentet fra
The Java Tutorials,
men litt tilpasset norske forhold.
Programmet leser inn tall (i form av sifferstrenger) fra fila
tall.txt
og summerer dem.
(Slik programmet er skrevet, med hardkoding av filsti for tallfil, må den plasseres på riktig
sted for at programmet skal finne den.) Tallfila har følgende innhold:
8,5 32767 3,14159 1000000,1
Legg merke til at den inneholder en blanding av hele tall og desimaltall, og at det er brukt komma som desimaltegn. Når programmet blir kjørt, vil det skrive ut følgede resultat:
1032778.74159
Her er programmets kildekode:
1 import java.io.FileReader; 2 import java.io.BufferedReader; 3 import java.io.IOException; 4 import java.util.Scanner; 5 6 public class ScanSum 7 { 8 public static void main(String[] args) throws IOException 9 { 10 double sum = 0; 11 try (Scanner s = new Scanner(new BufferedReader( 12 new FileReader("tall.txt")))) 13 { 14 while (s.hasNext()) 15 { 16 if (s.hasNextDouble()) 17 sum += s.nextDouble(); 18 else 19 s.next(); 20 } 21 } 22 System.out.println(sum); 23 } 24 }
Eksempel 3: Testprogram for regulære uttrykk
Dersom vi ønsker å sjekke om en gitt tekststreng er i samsvar med et
bestemt mønster, er det ikke alltid så lett å finne ut hvordan vi skal skrive
et korrekt regulært uttrykk for å beskrive vedkommende mønster. Programmet
RegexTestHarness
gjengitt nedenfor er en bearbeidet versjon av et program fra The Java
Tutorials. Programmets brukervindu er vist på følgende bilde.
I første tekstfeltet skriver man inn det regulære uttrykket (mønsteret) man vil teste på. Det blir lest inn og registrert når man trykker på returtasten. I det andre tekstfeltet skriver man inn den teksten man vil det skal søkes i. Deretter trykker man på returtasten. Søket blir da utført og resultatet blir skrevet ut i tekstområdet nedenfor.
1 import java.util.regex.*; 2 import javax.swing.*; 3 import java.awt.event.*; 4 import java.awt.*; 5 6 public class RegexTestHarness extends JFrame 7 { 8 private JTextField input1, input2; 9 private JTextArea utskrift; 10 private String reguttr, teststreng; 11 private Pattern pattern; 12 private Matcher matcher; 13 14 public RegexTestHarness() 15 { 16 input1 = new JTextField( 20 ); 17 input2 = new JTextField( 30 ); 18 utskrift = new JTextArea( 10, 40 ); 19 utskrift.setEditable( false ); 20 Container c = getContentPane(); 21 c.setLayout(new FlowLayout()); 22 c.add(new JLabel("Regulært uttrykk det skal testes på")); 23 c.add(input1); 24 c.add(new JLabel("Uttrykk det skal søkes i")); 25 c.add(input2); 26 c.add(new JScrollPane(utskrift)); 27 Inputlytter lytter = new Inputlytter(); 28 input1.addActionListener(lytter); 29 input2.addActionListener(lytter); 30 setSize( 500, 300 ); 31 setVisible(true); 32 } 33 34 public static void main(String[] args) 35 { 36 new RegexTestHarness(); 37 } 38 39 private class Inputlytter implements ActionListener 40 { 41 public void actionPerformed( ActionEvent e ) 42 { 43 if ( e.getSource() == input1 ) 44 { 45 try 46 { 47 reguttr = input1.getText(); 48 pattern = Pattern.compile(reguttr); 49 utskrift.setText(""); 50 } 51 catch ( PatternSyntaxException pe ) 52 { 53 utskrift.setText("Syntaksfeil i regulært uttrykk!" ); 54 } 55 } 56 else if ( e.getSource() == input2 ) 57 { 58 try 59 { 60 teststreng = input2.getText(); 61 matcher = pattern.matcher(teststreng); 62 boolean found = false; 63 while (matcher.find()) 64 { 65 utskrift.append("Jeg fant tekstkomponenten " + matcher.group() 66 + " med start i indeks " + matcher.start() 67 + " og slutt i indeks " + matcher.end() + "\n"); 68 found = true; 69 } 70 if(!found) 71 { 72 utskrift.append("Fant ikke noe som matchet.\n"); 73 } 74 } 75 catch ( NullPointerException ex) 76 { 77 utskrift.setText("Mangler mønster til å sammenlikne med!"); 78 } 79 } 80 } 81 } 82 }
Innholdsoversikt for programutvikling
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2015