Java-Tipp 112: Verbessern Sie die Tokenisierung informationsreicher Zeichenfolgen

Die meisten Java-Programmierer haben die java.util.StringTokenizerKlasse irgendwann einmal benutzt. Es ist eine praktische Klasse, die die Eingabezeichenfolge basierend auf einem Trennzeichen grundsätzlich tokenisiert (bricht) und die Token auf Anfrage bereitstellt. (Tokenisierung ist der Vorgang, bei dem Zeichenfolgen in Token umgewandelt werden, die von Ihrem Programm verstanden werden.)

Obwohl praktisch, ist StringTokenizerdie Funktionalität eingeschränkt. Die Klasse sucht einfach nach dem Trennzeichen in der Eingabezeichenfolge und unterbricht die Zeichenfolge, sobald das Trennzeichen gefunden wurde. Es wird weder nach Bedingungen gesucht, z. B. ob sich das Trennzeichen in einem Teilstring befindet, noch wird das Token als ""(Zeichenfolgenlänge 0) zurückgegeben, sobald zwei aufeinanderfolgende Trennzeichen in der Eingabe gefunden wurden. Um diese Einschränkungen zu erfüllen, wird die Java 2-Plattform (ab JDK 1.2) mit der BreakIteratorKlasse geliefert, bei der es sich um einen verbesserten Tokenizer handelt StringTokenizer. Da eine solche Klasse in JDK 1.1.x nicht vorhanden ist, verbringen Entwickler häufig viel Zeit damit, einen Original-Tokenizer zu schreiben, der ihre Anforderungen erfüllt. In einem großen Projekt mit Datenformatverarbeitung ist es nicht ungewöhnlich, dass viele solcher benutzerdefinierten Klassen im Umlauf sind.

Dieser Tipp soll Sie durch das Schreiben eines ausgeklügelten Tokenizers unter Verwendung des vorhandenen führen StringTokenizer.

StringTokenizer-Einschränkungen

Sie können eine erstellen, StringTokenizerindem Sie einen der folgenden drei Konstruktoren verwenden:

  1. StringTokenizer(String sInput): Bricht auf Leerzeichen ( " ", "\t", "\n").
  2. StringTokenizer(String sInput, String sDelimiter): Bricht weiter sDelimiter.
  3. StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens): Bricht ein sDelimiter, aber wenn bReturnTokenstrue festgelegt ist, wird das Trennzeichen auch als Token zurückgegeben.

Der erste Konstruktor prüft nicht, ob die Eingabezeichenfolge Teilzeichenfolgen enthält. Wenn die Zeichenfolge "hello. Today \"I am \" going to my home town"auf weißen Platz in Token aufgeteilt wird, ist das Ergebnis in Tokens ist hello., Today, "I, am, ", going, statt hello., Today, "I am ", going.

Der zweite Konstruktor überprüft nicht das aufeinanderfolgende Auftreten von Trennzeichen. Wenn die Zeichenfolge "book, author, publication,,,date published"auf wird in Token aufgeteilt ",", die StringTokenizerRenditen vier Token mit Werten book, author, publication, und date publishedstatt der sechs Werte book, author, publication, "", "", und date published, wo ""Mittel String der Länge 0. sechs zu erhalten, müssen Sie die Set StringTokenizer‚s - bReturnTokensParameter auf true.

Die Funktion zum Setzen des Parameters auf true ist wichtig, da sie eine Vorstellung vom Vorhandensein aufeinanderfolgender Trennzeichen vermittelt. Wenn die Daten beispielsweise dynamisch abgerufen und zum Aktualisieren einer Tabelle in einer Datenbank verwendet werden, in der die Eingabetoken den Spaltenwerten zugeordnet sind, können wir die Token nicht mit Datenbankspalten abbilden, da wir nicht sicher sind, welche Spalten festgelegt werden sollen zu "". Beispielsweise möchten wir einer Tabelle mit sechs Spalten Datensätze hinzufügen, und die Eingabedaten enthalten zwei aufeinanderfolgende Trennzeichen. Das Ergebnis von StringTokenizerin diesem Fall sind fünf Token (da zwei aufeinanderfolgende Trennzeichen das Token darstellen "", das StringTokenizervernachlässigt wird), und wir müssen sechs Felder setzen. Wir wissen auch nicht, wo das fortlaufende Trennzeichen erscheint, also auf welche Spalte gesetzt werden soll "".

Der dritte Konstruktor funktioniert nicht, wenn ein Token selbst (in Länge und Wert) dem Trennzeichen entspricht und sich in einem Teilstring befindet. Wenn der String in "book, author, publication,\",\",date published"Token aufgeteilt wird (dieser Zeichenfolge enthält , ,als Zeichen, die die gleichen wie seine Trennzeichen ist) auf Zeichenkette ,, ist das Ergebnis book, author, publication, ", ", date published(mit sechs Tokens) anstelle von book, author, publication, ,(das Kommazeichen), date published(mit fünf Token). Wohlgemerkt, selbst wenn Sie den bReturnTokens(dritten Parameter auf StringTokenizer) auf true setzen, hilft Ihnen dies in diesem Fall nicht weiter.

Grundbedürfnisse eines Tokenizers

Bevor Sie sich mit dem Code befassen, müssen Sie die Grundbedürfnisse eines guten Tokenizers kennen. Da Java - Entwickler auf die Verwendung von StringTokenizerKlasse, sollte ein guter tokenizer alle nützlichen Methoden haben diese Klasse bietet, wie zum Beispiel hasMoreTokens(), nextToken(), countTokens().

Der Code für diesen Tipp ist einfach und meist selbsterklärend. Grundsätzlich habe ich die StringTokenizerKlasse (erstellt mit bReturnTokensset to true) intern verwendet und die oben genannten Methoden bereitgestellt. Da in einigen Fällen das Trennzeichen als Token erforderlich ist (sehr seltene Fälle), in anderen Fällen nicht, muss der Tokenizer das Trennzeichen auf Anfrage als Token bereitstellen. Wenn Sie ein PowerfulTokenizerObjekt erstellen und nur die Eingabezeichenfolge und das Trennzeichen übergeben, wird intern ein StringTokenizerwith bReturnTokensset auf true verwendet. (Der Grund dafür ist, dass wenn a StringTokenizererstellt wird, ohne bReturnTokensauf true gesetzt zu sein, die zuvor genannten Probleme nur begrenzt überwunden werden können.) Um den Tokenizer ordnungsgemäß zu handhaben, prüft der Code bReturnTokensan einigen Stellen , ob er auf true gesetzt ist (Berechnung der Gesamtzahl der Token und nextToken()).

Wie Sie vielleicht bemerkt haben, PowerfulTokenizerimplementiert die EnumerationSchnittstelle realisieren so die hasMoreElements()und nextElement()Methoden , die den Anruf einfach delegieren hasMoreTokens()und nextToken()sind. (Durch die Implementierung der EnumerationSchnittstelle PowerfulTokenizerwird abwärtskompatibel mit StringTokenizer.) Betrachten wir ein Beispiel. Angenommen, die Eingabezeichenfolge ist "hello, Today,,, \"I, am \", going to,,, \"buy, a, book\""und das Trennzeichen ist ,. Diese Zeichenfolge gibt beim Token Werte zurück, wie in Tabelle 1 gezeigt:

Tabelle 1: Von Tokenized String zurückgegebene Werte
Art Anzahl der Token Token

StringTokenizer

(bReturnTokens = true)

19 hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book"(hier :trennt der Charakter die Token)

PowerfulTokenizer

(bReturnTokens = true)

13 hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book(wobei ""bedeutet Zeichenfolge der Länge 0)

PowerfulTokenizer

(bReturnTokens = false)

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

Die Eingabezeichenfolge enthält 11 Komma ( ,) -Zeichen, von denen sich drei innerhalb von Teilzeichenfolgen befinden und vier nacheinander angezeigt werden (wie Today,,,zwei aufeinanderfolgende Komma, wobei das erste Komma das TodayTrennzeichen ist). Hier ist die Logik bei der Berechnung der Anzahl der Token in dem PowerfulTokenizerFall:

  1. Im Fall von bReturnTokens=truemultiplizieren Sie die Anzahl der Begrenzer in Teilzeichenfolgen mit 2 und subtrahieren Sie diesen Betrag von der tatsächlichen Summe, um die Tokenanzahl zu erhalten. Der Grund dafür ist, für die Teilkette "buy, a, book", StringTokenizerwerden fünf Token zurückkehren (dh buy:,:a:,:book), während PowerfulTokenizerwird ein Rück Token (dh buy, a, book). Der Unterschied beträgt vier (dh 2 * Anzahl der Begrenzer innerhalb des Teilstrings). Diese Formel gilt für alle Teilzeichenfolgen, die Trennzeichen enthalten. Beachten Sie den Sonderfall, in dem das Token selbst dem Begrenzer entspricht. Dies sollte den Zählwert nicht verringern.
  2. In ähnlicher Weise bReturnTokens=falsesubtrahieren Sie für den Fall von den Wert des Ausdrucks [Gesamtzahl der Begrenzer (11) - aufeinanderfolgende Begrenzer (4) + Anzahl der Begrenzer innerhalb der Teilzeichenfolgen (3)] von der tatsächlichen Summe (19), um die Tokenanzahl zu erhalten. Da wir in diesem Fall die Begrenzer nicht zurückgeben, sind sie (ohne fortlaufend oder innerhalb von Teilzeichenfolgen) für uns nicht von Nutzen, und die obige Formel gibt die Gesamtzahl der Token an (9).

Denken Sie an diese beiden Formeln, die das Herzstück der PowerfulTokenizer. Diese Formeln funktionieren für fast alle Fälle. Wenn Sie jedoch komplexere Anforderungen haben, die für diese Formeln nicht geeignet sind, müssen Sie verschiedene Beispiele berücksichtigen, um Ihre eigene Formel zu entwickeln, bevor Sie mit der Codierung beginnen.

 // überprüfe, ob sich das Trennzeichen innerhalb eines Teilstrings für befindet (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 .