Java-Tipp 112: Verbessern Sie die Tokenisierung informationsreicher Zeichenfolgen
Die meisten Java-Programmierer haben die java.util.StringTokenizer
Klasse 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 StringTokenizer
die 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 BreakIterator
Klasse 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, StringTokenizer
indem Sie einen der folgenden drei Konstruktoren verwenden:
StringTokenizer(String sInput)
: Bricht auf Leerzeichen (" ", "\t", "\n"
).StringTokenizer(String sInput, String sDelimiter)
: Bricht weitersDelimiter
.StringTokenizer(String sInput, String sDelimiter, boolean bReturnTokens)
: Bricht einsDelimiter
, aber wennbReturnTokens
true 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 StringTokenizer
Renditen vier Token mit Werten book
, author
, publication
, und date published
statt 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 - bReturnTokens
Parameter 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 StringTokenizer
in diesem Fall sind fünf Token (da zwei aufeinanderfolgende Trennzeichen das Token darstellen ""
, das StringTokenizer
vernachlä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 StringTokenizer
Klasse, 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 StringTokenizer
Klasse (erstellt mit bReturnTokens
set 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 PowerfulTokenizer
Objekt erstellen und nur die Eingabezeichenfolge und das Trennzeichen übergeben, wird intern ein StringTokenizer
with bReturnTokens
set auf true verwendet. (Der Grund dafür ist, dass wenn a StringTokenizer
erstellt wird, ohne bReturnTokens
auf true gesetzt zu sein, die zuvor genannten Probleme nur begrenzt überwunden werden können.) Um den Tokenizer ordnungsgemäß zu handhaben, prüft der Code bReturnTokens
an einigen Stellen , ob er auf true gesetzt ist (Berechnung der Gesamtzahl der Token und nextToken()
).
Wie Sie vielleicht bemerkt haben, PowerfulTokenizer
implementiert die Enumeration
Schnittstelle realisieren so die hasMoreElements()
und nextElement()
Methoden , die den Anruf einfach delegieren hasMoreTokens()
und nextToken()
sind. (Durch die Implementierung der Enumeration
Schnittstelle PowerfulTokenizer
wird 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:
Art | Anzahl der Token | Token |
---|---|---|
|
19 | hello:,: Today:,:,:,: "I:,: am ":,: going to:,:,:,: "buy:,: a:,: book " (hier : trennt der Charakter die Token) |
|
13 | hello:,:Today:,:"":"":I, am:,:going to:,:"":"":buy a book (wobei "" bedeutet Zeichenfolge der Länge 0) |
|
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 Today
Trennzeichen ist). Hier ist die Logik bei der Berechnung der Anzahl der Token in dem PowerfulTokenizer
Fall:
- Im Fall von
bReturnTokens=true
multiplizieren 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"
,StringTokenizer
werden fünf Token zurückkehren (dhbuy:,:a:,:book
), währendPowerfulTokenizer
wird ein Rück Token (dhbuy, 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. - In ähnlicher Weise
bReturnTokens=false
subtrahieren 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; 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="" consecutive="" delimiters="" are="" found.="" (="" (sprevtoken.equals(sdelim))="" &&="" (stoken.equals(sdelim))="" )="" sprevtoken="sToken;" itokenno++;="" return="" "";="" check="" whether="" itself="" equal="" (stoken.trim().startswith("\""))="" (stoken.length()="=" 1)="" this="" special="" case="" when="" string="" snexttoken="oTokenizer.nextToken();" (!snexttoken.trim().endswith("\""))="" stoken="" stoken.substring(1,="" stoken.length()-1);="" there="" substring="" inside="" else="" (!((stoken.trim().endswith("\""))="" (!stoken.trim().endswith("\"\""))))="" (otokenizer.hasmoretokens())="" for="" presence="" "\"\""="" (!((snexttoken.trim().endswith("\""))="" (!snexttoken.trim().endswith("\"\"")))="" (!otokenizer.hasmoretokens())="" ;="" <="" re="">The
nextToken()
method gets tokens by usingStringTokenizer.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. IfnextToken()
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 .