De fleste Java-programmører har brugt java.util.StringTokenizer
klasse på et eller andet tidspunkt. Det er en praktisk klasse, der grundlæggende symboliserer (bryder) inputstrengen baseret på en separator og leverer tokens efter anmodning. (Tokenisering er handlingen med at omdanne sekvenser af tegn til tokens, der forstås af dit program.)
Selvom det er praktisk, StringTokenizer
's funktionalitet er begrænset. Klassen ser simpelthen efter afgrænseren i inputstrengen og bryder strengen, når afgrænseren er fundet. Det kontrollerer ikke for forhold som om afgrænseren er inden for en understreng, og det returnerer heller ikke tokenet som ""
(strenglængde 0), når to på hinanden følgende afgrænsere findes i input. For at opfylde disse begrænsninger følger Java 2-platformen (JDK 1.2 og frem) med BreakIterator
klasse, som er en forbedret tokenizer over StringTokenizer
. Da en sådan klasse ikke er til stede i JDK 1.1.x, bruger udviklere ofte meget tid på at skrive en original tokenizer, der opfylder deres krav. I et stort projekt, der involverer håndtering af dataformat, er det ikke ualmindeligt at finde mange sådanne tilpassede klasser flydende rundt.
Dette tip har til formål at guide dig gennem at skrive en sofistikeret tokenizer ved hjælp af den eksisterende StringTokenizer
.
StringTokenizer begrænsninger
Du kan oprette en StringTokenizer
ved hjælp af en af de følgende tre konstruktører:
StringTokenizer (String sInput)
: Brud på det hvide rum ("", "\ t", "\ n"
).StringTokenizer (String sInput, String sDelimiter)
: Bryder videres Afgrænser
.StringTokenizer (String sInput, String sDelimiter, boolean bReturnTokens)
: Bryder videres Afgrænser
, men hvisbReturnTokens
er sat til sand, så returneres afgrænseren også som et token.
Den første konstruktør kontrollerer ikke, om inputstrengen indeholder understrenge. Når strengen "hej. I dag \" skal jeg \ "til min hjemby"
er tokeniseret på hvidt rum, resultatet er i tokens Hej.
, I dag
, "JEG
, er
, "
, går
, i stedet for Hej.
, I dag
, "Jeg er "
, går
.
Den anden konstruktør kontrollerer ikke afgrænsernes fortløbende udseende. Når strengen "bog, forfatter, udgivelse ,,, udgivelsesdato"
er symboliseret den ","
, det StringTokenizer
returnerer fire tokens med værdier Bestil
, forfatter
, offentliggørelse
og dato offentliggjort
i stedet for de seks værdier Bestil
, forfatter
, offentliggørelse
, ""
, ""
og dato offentliggjort
, hvor ""
betyder streng med længde 0. For at få seks skal du indstille StringTokenizer
's bReturnTokens
parameter til sand.
Funktionen ved at indstille parameteren til sand er vigtig, da den giver en idé om tilstedeværelsen af på hinanden følgende afgrænsere. For eksempel, hvis dataene opnås dynamisk og bruges til at opdatere en tabel i en database, hvor input-tokens kortlægges til kolonneværdierne, kan vi ikke kortlægge tokens med databasekolonner, da vi ikke er sikre på, hvilke kolonner der skal indstilles til ""
. For eksempel vil vi føje poster til en tabel med seks kolonner, og inputdataene indeholder to på hinanden følgende afgrænsere. Resultatet fra StringTokenizer
i dette tilfælde er der fem tokens (som to på hinanden følgende afgrænsninger repræsenterer tokenet ""
, hvilken StringTokenizer
forsømmelser), og vi er nødt til at indstille seks felter. Vi ved heller ikke, hvor den på hinanden følgende afgrænsning vises, og dermed hvilken kolonne der skal indstilles til ""
.
Den tredje konstruktør fungerer ikke, hvis et token i sig selv er lig (i længde og værdi) til afgrænseren og er i en understreng. Når strengen "bog, forfatter, udgivelse, \", \ ", udgivelsesdato"
er tokeniseret (denne streng indeholder ,
som et token, som er det samme som dets afgrænser) på streng ,
, resultatet er Bestil
, forfatter
, offentliggørelse
, "
, "
, dato offentliggjort
(med seks poletter) i stedet for Bestil
, forfatter
, offentliggørelse
, ,
(kommategnet), dato offentliggjort
(med fem poletter). Husk dig, selv indstilling af bReturnTokens
(tredje parameter til StringTokenizer
) til sandt vil ikke hjælpe dig i dette tilfælde.
Grundlæggende behov for en tokenizer
Før du behandler koden, skal du kende de grundlæggende behov for en god tokenizer. Da Java-udviklere er vant til StringTokenizer
klasse, skal en god tokenizer have alle de nyttige metoder, som klassen giver, såsom hasMoreTokens ()
, nextToken ()
, countTokens ()
.
Koden til dette tip er enkel og for det meste selvforklarende. Dybest set har jeg brugt StringTokenizer
klasse (oprettet med bReturnTokens
indstillet til sand) internt og leverede metoder nævnt som ovenfor. Da afgrænseren i nogle tilfælde er påkrævet som tokens (meget sjældne tilfælde), mens det i nogle ikke er det, skal tokenizer levere afgrænsningen som et token efter anmodning. Når du opretter en PowerfulTokenizer
objekt, der kun videregiver inputstrengen og afgrænseren, bruger den internt en StringTokenizer
med bReturnTokens
indstillet til sandt. (Årsagen til dette er, hvis en StringTokenizer
er skabt uden bReturnTokens
indstillet til sand, så er det begrænset i at overvinde de tidligere nævnte problemer). For at håndtere tokenizer korrekt kontrollerer koden, om bReturnTokens
er sat til sand et par steder (beregning af det samlede antal tokens og nextToken ()
).
Som du måske har bemærket, PowerfulTokenizer
implementerer Optælling
interface, således implementering af hasMoreElements ()
og nextElement ()
metoder, der simpelthen delegerer opkaldet til hasMoreTokens ()
og nextToken ()
, henholdsvis. (Ved at implementere Optælling
interface, PowerfulTokenizer
bliver bagudkompatibel med StringTokenizer
Lad os overveje et eksempel. Sig, at inputstrengen er "hej, i dag ,,, \" jeg, er \ ", skal ,,, \" købe, en, bog \ ""
og afgrænseren er ,
. Denne streng når tokeniseret returnerer værdier som vist i tabel 1:
Type | Antal poletter | Poletter |
---|---|---|
| 19 | hej:,: I dag:,:,:,: "Jeg:,: er":,: går til:,:,:,: "køb:,: a:,: bog " (her karakteren : adskiller tokens) |
| 13 | hej:,: I dag:,: "": "": Jeg, er:,: går til:,: "": "": køb en bog (hvor "" betyder streng med længde 0) |
| 9 | hej: I dag: "": "": Jeg skal: "": "": købe en bog |
Inputstrengen indeholder 11 komma (,
) tegn, hvoraf tre er inde i understrenge og fire vises efter hinanden (som I dag,,,
laver to på hinanden følgende kommaoptrædener, hvor det første komma er I dag
afgrænser). Her er logikken i beregningen af antallet af tokens i PowerfulTokenizer
sag:
- I tilfælde af
bReturnTokens = sandt
multiplicerer antallet af afgrænsere inde i understrengene med 2 og trækker det beløb fra den faktiske sum for at få token-tællingen. Årsagen er, for underlaget"køb, en, bog"
,StringTokenizer
returnerer fem poletter (dvs.køb:,: a:,: bog
), mensPowerfulTokenizer
returnerer et token (dvs.køb, en, bog
). Forskellen er fire (dvs. 2 * antal afgrænsere inde i underlaget). Denne formel holder godt for ethvert underlag, der indeholder afgrænsere. Vær opmærksom på det specielle tilfælde, hvor selve symbolet er lig med afgrænseren; dette bør ikke mindske tællingsværdien. - Tilsvarende for tilfældet med
bReturnTokens = falsk
, fratræk udtrykkets værdi [total afgrænsere (11) - på hinanden følgende afgrænsere (4) + antal afgrænsere inden i understrenge (3)] fra det faktiske total (19) for at få token-tællingen. Da vi ikke returnerer afgrænserne i dette tilfælde, er de (uden at blive vist fortløbende eller inde i understrenge) ikke til nogen nytte for os, og ovenstående formel giver os det samlede antal tokens (9).
Husk disse to formler, som er hjertet i PowerfulTokenizer
. Disse formler fungerer i næsten alle respektive tilfælde. Men hvis du har mere komplekse krav, der ikke passer til disse formler, skal du overveje forskellige eksempler for at udvikle din egen formel, før du skynder dig at kode.
// kontroller, om afgrænseren er inden for 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;" }="" }="">
Det nextToken ()
metoden får tokens ved hjælp af StringTokenizer.nextToken
og kontrollerer det dobbelte citattegn i tokenet. Hvis metoden finder disse tegn, får den flere tokens, indtil den ikke finder nogen med et dobbelt citat. Det gemmer også tokenet i en variabel (sPrevToken
; se kildekode) til kontrol af på hinanden følgende afgrænsningsoptrædener. Hvis nextToken ()
finder fortløbende tokens, der er lig med skillelinjen, og returnerer derefter ""
(streng med længde 0) som token.
Tilsvarende er hasMoreTokens ()
metode kontrollerer, om antallet af allerede anmodede tokens er mindre end det samlede antal tokens.
Spar udviklingstid
Denne artikel har lært dig, hvordan du nemt skriver en stærk tokenizer. Ved hjælp af disse begreber kan du hurtigt skrive komplekse tokenizers, hvilket sparer dig betydelig udviklingstid.
Bhabani Padhi er en Java-arkitekt og programmør, der i øjeblikket arbejder på web- og enterprise-applikationsudvikling ved hjælp af Java-teknologi i UniteSys, Australien. Tidligere arbejdede han i Baltimore Technologies, Australien med e-sikkerhed produktudvikling og i Fujitsu, Australien på et EJB serverudviklingsprojekt. Bhabanis interesser inkluderer distribueret computing, mobil og webapplikationsudvikling ved hjælp af Java-teknologi.Lær mere om dette emne
- Få kildekoden til dette tip
//images.techhive.com/downloads/idge/imported/article/jvw/2001/06/powerfultokenizer.java
- For mere information om BreakIterator
//java.sun.com/products/jdk/1.2/docs/api/java/text/BreakIterator.html
- Se alle forrige Java-tip og indsend din egen
//www.javaworld.com/javatips/jw-javatips.index.html
- For mere Introduktionsniveau artikler, besøg JavaWorld 's Aktuelt indeks
//www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html
- Lær Java fra bunden i JavaWorld 's Java 101 kolonne
//www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html
- Java-eksperter besvarer dine hårdeste Java-spørgsmål i JavaWorld 's Java Q&A kolonne
//www.javaworld.com/javaworld/javaqa/javaqa-index.html
- Tilmeld dig JavaWorld denne uge gratis ugentligt e-mail-nyhedsbrev for at finde ud af, hvad der er nyt på JavaWorld
//www.idg.net/jw- abonnement
Denne historie, "Java Tip 112: Improve tokenization of information-rich strings" blev oprindeligt udgivet af JavaWorld.