De fleste Java-programmerere har brukt java.util.StringTokenizer
klasse på et eller annet tidspunkt. Det er en praktisk klasse som i utgangspunktet tokeniserer (bryter) inngangsstrengen basert på en separator, og leverer tokens på forespørsel. (Tokenization er å gjøre sekvenser av tegn til tokens som er forstått av programmet ditt.)
Selv om det er praktisk, StringTokenizer
funksjonalitet er begrenset. Klassen leter bare etter avgrenseren i inngangsstrengen og bryter strengen når avgrenseren er funnet. Den sjekker ikke for forhold som om avgrenseren er innenfor en understreng, og returnerer heller ikke tokenet som ""
(strenglengde 0) når to påfølgende avgrensere er funnet i inngangen. For å oppfylle disse begrensningene følger Java 2-plattformen (JDK 1.2 og fremover) med BreakIterator
klasse, som er en forbedret tokenizer over StringTokenizer
. Siden en slik klasse ikke er til stede i JDK 1.1.x, bruker utviklere ofte mye tid på å skrive en original tokenizer som oppfyller deres krav. I et stort prosjekt som involverer håndtering av dataformat, er det ikke uvanlig å finne mange slike tilpassede klasser som flyter rundt.
Dette tipset tar sikte på å veilede deg gjennom å skrive en sofistikert tokenizer ved å bruke den eksisterende StringTokenizer
.
StringTokenizer begrensninger
Du kan opprette en StringTokenizer
ved å bruke en av de følgende tre konstruktørene:
StringTokenizer (String sInput)
: Bryter på hvite mellomrom ("", "\ t", "\ n"
).StringTokenizer (String sInput, String sDelimiter)
: Bryter videreavgrenser
.StringTokenizer (String sInput, String sDelimiter, boolean bReturnTokens)
: Bryter videreavgrenser
, men hvisbReturnTokens
er satt til sant, så returneres også skillet som et token.
Den første konstruktøren sjekker ikke om inngangsstrengen inneholder understrenger. Når strengen "hallo. I dag \" skal jeg \ "til hjembyen min"
er tokenisert på hvit plass, er resultatet i tokens Hallo.
, I dag
, "JEG
, er
, "
, går
, i stedet for Hallo.
, I dag
, "Jeg er "
, går
.
Den andre konstruktøren sjekker ikke avgrensernes fortløpende utseende. Når strengen "bok, forfatter, utgivelse ,,, utgivelsesdato"
er tokenisert på ","
, den StringTokenizer
returnerer fire tokens med verdier bok
, forfatter
, utgivelse
, og dato publisert
i stedet for de seks verdiene bok
, forfatter
, utgivelse
, ""
, ""
, og dato publisert
, hvor ""
betyr streng med lengde 0. For å få seks må du stille inn StringTokenizer
s bReturnTokens
parameter til sann.
Funksjonen ved å sette parameteren til sant er viktig, da den gir en ide om tilstedeværelsen av påfølgende avgrensere. For eksempel, hvis dataene oppnås dynamisk og brukes til å oppdatere en tabell i en database, der inngangstokenene tilordnes til kolonneverdiene, kan vi ikke tilordne tokens med databasekolonner, da vi ikke er sikre på hvilke kolonner som skal settes til ""
. For eksempel vil vi legge til poster i en tabell med seks kolonner, og inndataene inneholder to påfølgende avgrensere. Resultatet fra StringTokenizer
i dette tilfellet er fem tokens (ettersom to påfølgende avgrensninger representerer token ""
, hvilken StringTokenizer
forsømmelser), og vi må sette seks felt. Vi vet heller ikke hvor den påfølgende avgrenseren vises, og dermed hvilken kolonne som skal settes til ""
.
Den tredje konstruktøren vil ikke fungere hvis et token i seg selv er lik (i lengde og verdi) til avgrenseren og er i en understreng. Når strengen "bok, forfatter, publikasjon, \", \ ", publiseringsdato"
er tokenisert (denne strengen inneholder ,
som et token, som er det samme som avgrenseren) på streng ,
, resultatet er bok
, forfatter
, utgivelse
, "
, "
, dato publisert
(med seks tokens) i stedet for bok
, forfatter
, utgivelse
, ,
(kommategnet), dato publisert
(med fem poletter). Husk deg, til og med å sette inn bReturnTokens
(tredje parameter til StringTokenizer
) til sant vil ikke hjelpe deg i dette tilfellet.
Grunnleggende behov for en tokenizer
Før du håndterer koden, må du vite de grunnleggende behovene til en god tokenizer. Siden Java-utviklere er vant til StringTokenizer
klasse, bør en god tokenizer ha alle de nyttige metodene som klassen gir, for eksempel hasMoreTokens ()
, nextToken ()
, countTokens ()
.
Koden for dette tipset er enkel og for det meste selvforklarende. I utgangspunktet har jeg brukt StringTokenizer
klasse (opprettet med bReturnTokens
satt til sant) internt og ga metoder nevnt som ovenfor. Siden i noen tilfeller skilletegn kreves som tokens (svært sjeldne tilfeller) mens det i noen ikke er det, må tokenizer levere skilletegn som et token på forespørsel. Når du oppretter en PowerfulTokenizer
objektet, som bare overfører inngangsstrengen og avgrenseren, bruker den internt en StringTokenizer
med bReturnTokens
satt til sant. (Årsaken til dette er hvis en StringTokenizer
er skapt uten bReturnTokens
satt til sant, så er det begrenset i å overvinne problemene som er nevnt tidligere). For å håndtere tokenizer riktig, sjekker koden om bReturnTokens
er satt til sant noen få steder (beregner totalt antall tokens og nextToken ()
).
Som du kanskje har observert, PowerfulTokenizer
implementerer Oppregning
grensesnitt, og dermed implementere hasMoreElements ()
og nextElement ()
metoder som bare delegerer samtalen til hasMoreTokens ()
og nextToken ()
, henholdsvis. (Ved å implementere Oppregning
grensesnitt, PowerfulTokenizer
blir bakoverkompatibel med StringTokenizer
.) La oss se på et eksempel. Si at inngangsstrengen er "hallo, i dag ,,, \" Jeg, er \ ", skal ,,, \" kjøpe, en, bok \ ""
og avgrenseren er ,
. Denne strengen når tokenisert returnerer verdier som vist i tabell 1:
Type | Antall poletter | Tokens |
---|---|---|
| 19 | hallo:,: I dag:,:,:,: "Jeg:,: er":,: går til:,:,:,: "kjøp:,: a:,: bok " (her karakteren : skiller tokens) |
| 13 | hei:,: I dag:,: "": "": Jeg, er:,: skal til:,: "": "": kjøp en bok (hvor "" betyr lengde streng 0) |
| 9 | hallo: I dag: "": "": Jeg skal: "": "": kjøpe en bok |
Inngangsstrengen inneholder 11 komma (,
) tegn, hvorav tre er inne i understreng og fire vises fortløpende (som I dag,,,
gjør to påfølgende kommaopptredener, det første kommaet er I dag
skilletegn). Her er logikken i å beregne antall tokens i PowerfulTokenizer
sak:
- I tilfelle av
bReturnTokens = true
multipliser antall avgrensere inne i understrengene med 2 og trekk det beløpet fra den faktiske summen for å få token. Årsaken er, for substring"kjøp, en, bok"
,StringTokenizer
vil returnere fem tokens (dvs.kjøp:,: a:,: bok
), samtidig somPowerfulTokenizer
vil returnere ett token (dvs.kjøp, en, bok
). Forskjellen er fire (dvs. 2 * antall avgrensere inne i underlaget). Denne formelen holder godt for alle underlag som inneholder avgrensere. Vær oppmerksom på det spesielle tilfellet der selve symbolet tilsvarer avgrenseren; dette skal ikke redusere telleverdien. - Tilsvarende for saken om
bReturnTokens = falske
, trekk verdien av uttrykket [total avgrensere (11) - påfølgende avgrensere (4) + antall avgrensere inne i understrengene (3)] fra den faktiske summen (19) for å få token. Siden vi ikke returnerer avgrensningene i dette tilfellet, er de (uten å vises sammenhengende eller inne i understrengene) til ingen nytte for oss, og formelen ovenfor gir oss totalt antall tokens (9).
Husk disse to formlene, som er hjertet til PowerfulTokenizer
. Disse formlene fungerer i nesten alle tilfeller. Men hvis du har mer komplekse krav som ikke passer for disse formlene, må du vurdere forskjellige eksempler for å utvikle din egen formel før du skynder deg å kode.
// sjekk om avgrenseren er innenfor en understreng for (int i = 1; iThe
countTokens()
method checks whether the input string contains double quotes. If it does, then it decrements the count and updates the index to the index of the next double quote in that string (as shown in the above code segment). IfbReturnTokens
is false, then it decrements the count by the total number of nonsubsequent delimiters present in the input string.// return " "="" as="" token="" if="" consecutive="" delimiters="" are="" found.="" if="" (="" (sprevtoken.equals(sdelim))="" &&="" (stoken.equals(sdelim))="" )="" {="" sprevtoken="sToken;" itokenno++;="" return="" "";="" }="" check="" whether="" the="" token="" itself="" is="" equal="" to="" the="" delimiter="" if="" (="" (stoken.trim().startswith("\""))="" &&="" (stoken.length()="=" 1)="" )="" {="" this="" is="" a="" special="" case="" when="" token="" itself="" is="" equal="" to="" delimiter="" string="" snexttoken="oTokenizer.nextToken();" while="" (!snexttoken.trim().endswith("\""))="" {="" stoken="" +="sNextToken;" snexttoken="oTokenizer.nextToken();" }="" stoken="" +="sNextToken;" sprevtoken="sToken;" itokenno++;="" return="" stoken.substring(1,="" stoken.length()-1);="" }="" check="" whether="" there="" is="" a="" substring="" inside="" the="" string="" else="" if="" (="" (stoken.trim().startswith("\""))="" &&="" (!((stoken.trim().endswith("\""))="" &&="" (!stoken.trim().endswith("\"\""))))="" )="" {="" if="" (otokenizer.hasmoretokens())="" {="" string="" snexttoken="oTokenizer.nextToken();" check="" for="" presence="" of="" "\"\""="" while="" (!((snexttoken.trim().endswith("\""))="" &&="" (!snexttoken.trim().endswith("\"\"")))="" )="" {="" stoken="" +="sNextToken;" if="" (!otokenizer.hasmoretokens())="" {="" snexttoken="" ;="" break;="" }="" snexttoken="oTokenizer.nextToken();" }="" stoken="" +="sNextToken;" }="" }="">
De nextToken ()
metoden får tokens ved hjelp av StringTokenizer.nextToken
, og ser etter dobbel sitattegn i token. Hvis metoden finner disse tegnene, får den flere tokens til den ikke finner noen med et dobbelt sitat. Det lagrer også token i en variabel (sPrevToken
; se kildekode) for å kontrollere påfølgende avgrensningsopptredener. Hvis nextToken ()
finner påfølgende tokens som er lik avgrenseren, så returnerer den ""
(streng med lengde 0) som token.
Tilsvarende hasMoreTokens ()
metoden sjekker om antall poletter som allerede er forespurt er mindre enn totalt antall poletter.
Spar utviklingstid
Denne artikkelen har lært deg hvordan du enkelt kan skrive en kraftig tokenizer. Ved å bruke disse konseptene kan du skrive komplekse tokenisatorer raskt, og dermed spare deg for betydelig utviklingstid.
Bhabani Padhi er en Java-arkitekt og programmerer som for tiden jobber med utvikling av nett- og bedriftsapplikasjoner ved bruk av Java-teknologi i UniteSys, Australia. Tidligere jobbet han i Baltimore Technologies, Australia med produktutvikling for e-sikkerhet og i Fujitsu, Australia på et EJB-serverutviklingsprosjekt. Bhabanis interesser inkluderer distribuert databehandling, mobil og webapplikasjonsutvikling ved hjelp av Java-teknologi.Lær mer om dette emnet
- Få kildekoden for dette tipset
//images.techhive.com/downloads/idge/imported/article/jvw/2001/06/powerfultokenizer.java
- For mer informasjon om BreakIterator
//java.sun.com/products/jdk/1.2/docs/api/java/text/BreakIterator.html
- Vis alle forrige Java-tips og send inn dine egne
//www.javaworld.com/javatips/jw-javatips.index.html
- For mer Introduksjonsnivå artikler, besøk JavaWorld 's Aktuell indeks
//www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html
- Lær Java fra grunnen av i JavaWorld 's Java 101 kolonne
//www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html
- Java-eksperter svarer på de tøffeste Java-spørsmålene dine i JavaWorld 's Java Q&A kolonne
//www.javaworld.com/javaworld/javaqa/javaqa-index.html
- Registrer deg for JavaWorld denne uken gratis ukentlig e-post nyhetsbrev for å finne ut hva som er nytt på JavaWorld
//www.idg.net/jw-abonnement
Denne historien, "Java Tip 112: Improve tokenization of information-rich strings" ble opprinnelig utgitt av JavaWorld.