Programmering

Java Tip 112: Forbedre tokenisering af informationsrige strenge

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:

  1. StringTokenizer (String sInput): Brud på det hvide rum ("", "\ t", "\ n").
  2. StringTokenizer (String sInput, String sDelimiter): Bryder videre s Afgrænser.
  3. StringTokenizer (String sInput, String sDelimiter, boolean bReturnTokens): Bryder videre s Afgrænser, men hvis bReturnTokens 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ørelseog 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 StringTokenizerLad 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:

Tabel 1: Værdier returneret med tokeniseret streng
TypeAntal poletterPoletter

StringTokenizer

(bReturnTokens = sand)

19hej:,: I dag:,:,:,: "Jeg:,: er":,: går til:,:,:,: "køb:,: a:,: bog" (her karakteren : adskiller tokens)

PowerfulTokenizer

(bReturnTokens = sand)

13hej:,: I dag:,: "": "": Jeg, er:,: går til:,: "": "": køb en bog (hvor "" betyder streng med længde 0)

PowerfulTokenizer

(bReturnTokens = false)

9hej: 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 dagafgrænser). Her er logikken i beregningen af ​​antallet af tokens i PowerfulTokenizer sag:

  1. I tilfælde af bReturnTokens = sandtmultiplicerer 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), mens PowerfulTokenizer 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.
  2. 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; i

Det nextToken () metoden får tokens ved hjælp af StringTokenizer.nextTokenog 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.