Java savjet 112: Poboljšajte tokenizaciju nizova bogatih informacijama

Većina programera Java koristila je java.util.StringTokenizerklasu u neko vrijeme. To je praktična klasa koja u osnovi tokenizira (razbija) ulazni niz na temelju separatora i na zahtjev daje tokene. (Tokenizacija je čin pretvaranja sekvenci znakova u žetone koje vaš program razumije.)

Iako je zgodan, StringTokenizerfunkcionalnost korisnika je ograničena. Klasa jednostavno traži graničnik u ulaznom nizu i prekida niz kad se graničnik pronađe. Ne provjerava uvjete poput je li graničnik unutar podniza niti vraća token kao ""(duljina niza 0) nakon što se dva uzastopna graničnika nađu na ulazu. Da bi ispunila ta ograničenja, Java 2 platforma (JDK 1.2 nadalje) dolazi s BreakIteratorklasom, koja je poboljšani tokenizer StringTokenizer. Budući da takva klasa nije prisutna u JDK 1.1.x, programeri često provode puno vremena pišući izvorni tokenizer koji ispunjava njihove zahtjeve. U velikom projektu koji uključuje rukovanje formatom podataka, nije rijetkost pronaći mnogo takvih prilagođenih klasa kako plutaju.

Ovaj savjet ima za cilj voditi vas kroz pisanje sofisticiranog tokenizera, koristeći postojeće StringTokenizer.

Ograničenja StringTokenizera

Možete stvoriti StringTokenizerpomoću bilo kojeg od sljedeća tri konstruktora:

  1. StringTokenizer(String sInput): Prekidi na praznom prostoru ( " ", "\t", "\n").
  2. StringTokenizer(String sInput, String sDelimiter): Prekida se sDelimiter.
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens): Prekida sDelimiter, ali ako bReturnTokensje postavljeno na true, graničnik se također vraća kao znak.

Prvi konstruktor ne provjerava sadrži li ulazni niz podnizove. Kada je niz "hello. Today \"I am \" going to my home town"se tokenized na bijelom prostoru, rezultat je u tokena hello., Today, "I, am, ", going, umjesto hello., Today, "I am ", going.

Drugi konstruktor ne provjerava uzastopni izgled graničnika. Kada se niz "book, author, publication,,,date published"je tokenized na ","The StringTokenizervraća četiri žetona s vrijednostima book, author, publicationi date publishedumjesto šest vrijednosti book, author, publication, "", "", i date published, gdje je ""sredstvo niz duljine 0. Da biste dobili šest, morate postaviti StringTokenizer„s bReturnTokensparametar istina.

Značajka postavljanja parametra na true je važna jer daje ideju o prisutnosti uzastopnih graničnika. Na primjer, ako se podaci dobivaju dinamički i koriste za ažuriranje tablice u bazi podataka, gdje se ulazni tokeni preslikavaju na vrijednosti stupaca, tada tokene ne možemo mapirati sa stupcima baze podataka jer nismo sigurni koje stupce treba postaviti do "". Na primjer, želimo dodati zapise u tablicu sa šest stupaca, a ulazni podaci sadrže dva uzastopna graničnika. Rezultat StringTokenizeru ovom slučaju je pet tokena (jer dva uzastopna graničnika predstavljaju žeton "", koji StringTokenizerzanemaruje), a mi moramo postaviti šest polja. Također ne znamo gdje se pojavljuje uzastopni graničnik, pa na koji stupac treba postaviti "".

Treći konstruktor neće raditi ako je sam token jednak (dužini i vrijednosti) graničniku i nalazi se u podnizu. Kada se niz "book, author, publication,\",\",date published"je tokenized (ovaj niz sadrži ,kao znak, koji je isti kao njezin graničnik) na žici ,, rezultat je book, author, publication, ", ", date published(sa šest žetona) umjesto book, author, publication, ,(zarez znakova), date published(s pet žetona). Imajte na umu, čak i ako postavite bReturnTokens(treći parametar na StringTokenizer) na true, u ovom vam slučaju neće pomoći.

Osnovne potrebe tokenizera

Prije nego što se pozabavite kodom, morat ćete znati osnovne potrebe dobrog tokenizera. Budući da se Java programeri koriste za StringTokenizerklasu, dobar tokenizer trebao imati sve korisne metode koje klase pruža, kao što je hasMoreTokens(), nextToken(), countTokens().

Kôd ovog savjeta je jednostavan i uglavnom je samorazumljiv. U osnovi, interno sam koristio StringTokenizerklasu (stvorenu s bReturnTokenspostavkom true) i pružao gore spomenute metode. Budući da je u nekim slučajevima graničnik potreban kao tokeni (vrlo rijetki slučajevi), dok u nekim nije, tokenizer mora na zahtjev dostaviti graničnik kao token. Kada kreirate PowerfulTokenizerobjekt, prosljeđujući samo ulazni niz i graničnik, on interno koristi StringTokenizersa bReturnTokensset na true. (Razlog tome je ako StringTokenizerje a stvoren bez bReturnTokenspostavljanja na true, tada je ograničen u prevladavanju prethodno navedenih problema). Da bi pravilno radio tokenizer, kôd provjerava je li bReturnTokensna nekoliko mjesta postavljeno na true (izračunavajući ukupan broj tokena i nextToken()).

Kao što ste možda primijetili, PowerfulTokenizerimplementira Enumerationsučelje, a koje prema hasMoreElements()i nextElement()metode koje jednostavno prenijeti poziv hasMoreTokens()i nextToken(), respektivno. (Implementacijom Enumerationsučelja PowerfulTokenizerpostaje unatrag kompatibilno s StringTokenizer.) Razmotrimo primjer. Recimo da je ulazni niz je, "hello, Today,,, \"I, am \", going to,,, \"buy, a, book\""a graničnik je ,. Ovaj niz kada se tokenizira vraća vrijednosti kao što je prikazano u tablici 1:

Tablica 1: Vrijednosti vraćene tokeniziranim nizom
Tip Broj žetona Žetoni

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(ovdje znak :odvaja žetone)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(gdje ""znači niz duljine 0)

PowerfulTokenizer

(bReturnTokens = false)

9 hello:Today:"":"":I am:going to:"":"":buy a book

Ulazni niz sadrži 11 ,znakova ( ), od kojih su tri unutar podniza, a četiri se pojavljuju uzastopno (što Today,,,čini dva uzastopna pojavljivanja zareza, a prva zarez Todayje razgraničenje). Evo logike u izračunavanju broja tokena u PowerfulTokenizerslučaju:

  1. U slučaju bReturnTokens=true, pomnožite broj graničnika unutar podniza s 2 i oduzmite taj iznos od stvarnog zbroja da biste dobili broj tokena. Razlog je, za podniz "buy, a, book", StringTokenizervratiti će se pet žetona (tj buy:,:a:,:book), dok PowerfulTokenizerće se vratiti jedan znak (tj buy, a, book). Razlika je četiri (tj. 2 * broja graničnika unutar podniza). Ova formula dobro vrijedi za bilo koji podniz koji sadrži graničnike. Budite svjesni posebnog slučaja kada je sam token jednak graničniku; to ne bi trebalo smanjiti vrijednost brojanja.
  2. Slično tome, za bReturnTokens=falsestvar od ukupne vrijednosti tokena (19) oduzmite vrijednost izraza [ukupni graničnici (11) - uzastopni graničnici (4) + broj graničnika unutar podniza (3)] od stvarnog zbroja (19). Budući da u ovom slučaju ne vraćamo graničnike, oni nam (bez da se pojavljuju uzastopno ili unutar podniza) ne koriste, a gornja formula daje nam ukupan broj tokena (9).

Sjetite se ove dvije formule, koje su srce PowerfulTokenizer. Te formule rade za gotovo sve odgovarajuće slučajeve. Međutim, ako imate složenije zahtjeve koji nisu prikladni za ove formule, morate razmotriti razne primjere kako biste razvili vlastitu formulu prije nego što požurite s kodiranjem.

 // provjeravamo je li graničnik unutar podniza for (int i = 1; i
   
    

nextToken()Način dobiva žetone pomoću gumba StringTokenizer.nextTokeni provjere za citat karaktera dvostrukim u tokena. Ako metoda pronađe te znakove, dobiva više tokena sve dok ih ne pronađe s dvostrukim navodnikom. Također pohranjuje token u varijablu ( sPrevToken; vidi izvorni kod) za provjeru uzastopnih pojavljivanja graničnika. Ako nextToken()pronađe uzastopne tokene koji su jednaki graničniku, tada se vraća ""(niz s duljinom 0) kao token.

Slično tome, hasMoreTokens()metoda provjerava je li broj već traženih tokena manji od ukupnog broja tokena.

Uštedite vrijeme za razvoj

Ovaj vas je članak naučio kako lako napisati moćan tokenizer. Koristeći ove koncepte, možete brzo pisati složene tokenizere, čime ćete uštedjeti značajno vrijeme za razvoj.

Bhabani Padhi je Java arhitekt i programer koji trenutno radi na razvoju web-a i poduzeća pomoću Java tehnologije u tvrtki UniteSys u Australiji. Prije toga radio je u tvrtki Baltimore Technologies u Australiji na razvoju proizvoda za e-sigurnost i u tvrtki Fujitsu u Australiji na projektu razvoja EJB poslužitelja. Interesi Bhabanija uključuju raspodijeljeno računanje, mobilne uređaje i razvoj web aplikacija korištenjem Java tehnologije.

Saznajte više o ovoj temi

  • Pronađite izvorni kod za ovaj savjet

    //images.techhive.com/downloads/idge/imported/article/jvw/2001/06/powerfultokenizer.java

  • Za više informacija o BreakIteratoru

    //java.sun.com/products/jdk/1.2/docs/api/java/text/BreakIterator.html

  • Pogledajte sve prethodne Java savjete i pošaljite svoje

    //www.javaworld.com/javatips/jw-javatips.index.html

  • For more Intro Level articles, visit JavaWorld's Topical Index

    //www.javaworld.com/javaworld/topicalindex/jw-ti-introlevel.html

  • Learn Java from the ground up in JavaWorld's Java 101 column

    //www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html

  • Java experts answer your toughest Java questions in JavaWorld's Java Q&A column

    //www.javaworld.com/javaworld/javaqa/javaqa-index.html

  • Sign up for the JavaWorld This Week free weekly email newsletter to find out what's new on JavaWorld

    //www.idg.net/jw-subscribe

Ovu je priču "Java tip 112: Poboljšati tokenizaciju nizova bogatih informacijama" izvorno objavio JavaWorld.