Suggerimento Java 112: migliora la tokenizzazione di stringhe ricche di informazioni

La maggior parte dei programmatori Java ha utilizzato la java.util.StringTokenizerclasse prima o poi. È una pratica classe che fondamentalmente tokenizza (interrompe) la stringa di input in base a un separatore e fornisce i token su richiesta. (La tokenizzazione è l'atto di trasformare sequenze di caratteri in gettoni che vengono compresi dal tuo programma.)

Sebbene utile, StringTokenizerla funzionalità di è limitata. La classe cerca semplicemente il delimitatore nella stringa di input e interrompe la stringa una volta trovato il delimitatore. Non controlla le condizioni come se il delimitatore si trovi all'interno di una sottostringa, né restituisce il token come ""(stringa di lunghezza 0) una volta trovati due delimitatori consecutivi nell'input. Per soddisfare queste limitazioni, la piattaforma Java 2 (JDK 1.2 in poi) viene fornita con la BreakIteratorclasse, che è un tokenizer migliorato StringTokenizer. Poiché tale classe non è presente in JDK 1.1.x, gli sviluppatori spesso impiegano molto tempo a scrivere un tokenizer originale che soddisfi i loro requisiti. In un grande progetto che coinvolge la gestione del formato dei dati, non è raro trovare molte di queste classi personalizzate che fluttuano.

Questo suggerimento mira a guidarti attraverso la scrittura di un sofisticato tokenizer, utilizzando l'esistente StringTokenizer.

Limitazioni di StringTokenizer

È possibile creare un StringTokenizerutilizzando uno qualsiasi dei seguenti tre costruttori:

  1. StringTokenizer(String sInput): Interruzioni su uno spazio bianco ( " ", "\t", "\n").
  2. StringTokenizer(String sInput, String sDelimiter): Si interrompe sDelimiter.
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens): Si interrompe sDelimiter, ma se bReturnTokensè impostato su true, anche il delimitatore viene restituito come token.

Il primo costruttore non controlla se la stringa di input contiene sottostringhe. Quando la stringa "hello. Today \"I am \" going to my home town"è formato token sullo spazio bianco, il risultato è in gettoni hello., Today, "I, am, ", going, invece di hello., Today, "I am ", going.

Il secondo costruttore non controlla l'aspetto consecutivo dei delimitatori. Quando la stringa "book, author, publication,,,date published"è con token su ",", i StringTokenizerrendimenti quattro gettoni con valori book, author, publication, e date publishedal posto dei sei valori book, author, publication, "", "", e date published, dove ""i mezzi stringa di lunghezza 0. Per ottenere sei, è necessario impostare il StringTokenizer's bReturnTokensparametro su true.

La caratteristica di impostare il parametro su true è importante in quanto dà un'idea della presenza di delimitatori consecutivi. Ad esempio, se i dati vengono ottenuti dinamicamente e utilizzati per aggiornare una tabella in un database, dove i token di input sono mappati ai valori delle colonne, non possiamo mappare i token con le colonne del database poiché non siamo sicuri di quali colonne devono essere impostate a "". Ad esempio, vogliamo aggiungere record a una tabella con sei colonne e i dati di input contengono due delimitatori consecutivi. Il risultato da StringTokenizerin questo caso è cinque token (poiché due delimitatori consecutivi rappresentano il token "", che StringTokenizertrascura), e dobbiamo impostare sei campi. Inoltre, non sappiamo dove appare il delimitatore consecutivo, quindi su quale colonna deve essere impostata "".

Il terzo costruttore non funzionerà se un token stesso è uguale (in lunghezza e valore) al delimitatore e si trova in una sottostringa. Quando la stringa "book, author, publication,\",\",date published"viene con token (questa stringa contiene ,come un token, che è la stessa come delimitatore) su stringa ,, il risultato è book, author, publication, ", ", date published(con sei gettoni) anziché book, author, publication, ,(il carattere virgola), date published(con cinque gettoni). Intendiamoci, anche impostare il bReturnTokens(terzo parametro su StringTokenizer) su true non ti aiuterà in questo caso.

Esigenze di base di un tokenizer

Prima di occuparti del codice, dovrai conoscere le esigenze di base di un buon tokenizer. Dal momento che gli sviluppatori Java sono utilizzati per la StringTokenizerclasse, un buon tokenizzatore dovrebbe avere tutti i metodi utili che classe fornisce, ad esempio hasMoreTokens(), nextToken(), countTokens().

Il codice per questo suggerimento è semplice e per lo più autoesplicativo. Fondamentalmente, ho usato internamente la StringTokenizerclasse (creata con bReturnTokensimpostato su true) e ho fornito i metodi menzionati sopra. Poiché in alcuni casi il delimitatore è richiesto come token (casi molto rari) mentre in alcuni non lo è, il tokenizer deve fornire il delimitatore come token su richiesta. Quando crei un PowerfulTokenizeroggetto, passando solo la stringa di input e il delimitatore, internamente utilizza un StringTokenizercon bReturnTokensimpostato su true. (La ragione di ciò è che se a StringTokenizerviene creato senza essere bReturnTokensimpostato su true, è limitato nel superare i problemi indicati in precedenza). Per gestire correttamente il tokenizer, il codice controlla se bReturnTokensè impostato su true in alcuni punti (calcolando il numero totale di token e nextToken()).

Come avrai notato, PowerfulTokenizerimplementa l' Enumerationinterfaccia, implementando così i metodi hasMoreElements()e nextElement()che delegano semplicemente la chiamata a hasMoreTokens()e nextToken(), rispettivamente. (Implementando l' Enumerationinterfaccia, PowerfulTokenizerdiventa retrocompatibile con StringTokenizer.) Consideriamo un esempio. Supponiamo che la stringa di input sia "hello, Today,,, \"I, am \", going to,,, \"buy, a, book\""e il delimitatore sia ,. Questa stringa quando tokenizzata restituisce valori come mostrato nella Tabella 1:

Tabella 1: valori restituiti dalla stringa tokenizzata
genere Numero di token Gettoni

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(qui il personaggio :separa i gettoni)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(dove ""significa stringa di lunghezza 0)

PowerfulTokenizer

(bReturnTokens = false)

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

La stringa di input contiene 11 caratteri virgola ( ,), di cui tre sono all'interno di sottostringhe e quattro appaiono consecutivamente (come Today,,,fa due apparizioni virgola consecutive, la prima virgola è Todayil delimitatore). Ecco la logica nel calcolare il numero di gettoni nel PowerfulTokenizercaso:

  1. Nel caso di bReturnTokens=true, moltiplica il numero di delimitatori all'interno delle sottostringhe per 2 e sottrai tale importo dal totale effettivo per ottenere il conteggio dei token. Il motivo è che, per la sottostringa "buy, a, book", StringTokenizerrestituirà cinque token (cioè, buy:,:a:,:book), mentre PowerfulTokenizerrestituirà un token (cioè, buy, a, book). La differenza è quattro (cioè 2 * numero di delimitatori all'interno della sottostringa). Questa formula è valida per qualsiasi sottostringa contenente delimitatori. Essere consapevoli del caso speciale in cui il token stesso è uguale al delimitatore; questo non dovrebbe diminuire il valore di conteggio.
  2. Allo stesso modo, nel caso di bReturnTokens=false, sottrarre il valore dell'espressione [delimitatori totali (11) - delimitatori consecutivi (4) + numero di delimitatori all'interno di sottostringhe (3)] dal totale effettivo (19) per ottenere il conteggio dei token. Dato che in questo caso non restituiamo i delimitatori, essi (senza apparire consecutivamente o all'interno di sottostringhe) non ci servono e la formula sopra ci fornisce il numero totale di token (9).

Ricorda queste due formule, che sono il cuore del PowerfulTokenizer. Queste formule funzionano per quasi tutti i rispettivi casi. Tuttavia, se hai requisiti più complessi che non sono adatti per queste formule, devi considerare vari esempi per sviluppare la tua formula prima di precipitarti nella codifica.

 // controlla se il delimitatore è all'interno di una sottostringa per (int i = 1; i
   
    

The nextToken() method gets tokens by using StringTokenizer.nextToken, and checks for the double quote character in the token. If the method finds those characters, it gets more tokens until it doesn't find any with a double quote. It also stores the token in a variable (sPrevToken; see source code) for checking consecutive delimiter appearances. If nextToken() finds consecutive tokens that are equal to the delimiter, then it returns "" (string with length 0) as the token.

Similarly, the hasMoreTokens() method checks whether the number of tokens already requested is less than the total number of tokens.

Save development time

This article has taught you how to easily write a powerful tokenizer. Using these concepts, you can write complex tokenizers quickly, thus saving you significant development time.

Bhabani Padhi is a Java architect and programmer currently working on Web and enterprise application development using Java technology at UniteSys, Australia. Previously he worked at Baltimore Technologies, Australia on e-security product development and at Fujitsu, Australia on an EJB server development project. Bhabani's interests include distributed computing, mobile, and Web application development using Java technology.

Learn more about this topic

  • Get the source code for this tip

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

  • For more information on BreakIterator

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

  • View all previous Java Tips and submit your own

    //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

This story, "Java Tip 112: Improve tokenization of information-rich strings" was originally published by JavaWorld .