Galileo Computing < openbook >
Galileo Computing - Programming the Net
Galileo Computing - Programming the Net


Java ist auch eine Insel (2. Aufl.) von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 1.4
Java ist auch eine Insel (2. Auflage)
gp Kapitel 4 Der Umgang mit Zeichenketten
  gp 4.1 Strings und deren Anwendung
  gp 4.2 Veränderbare Zeichenketten mit der Klasse StringBuffer
    gp 4.2.1 Anlegen von StringBuffer-Objekten
    gp 4.2.2 Die Länge eines StringBuffer-Objekts lesen und setzen
    gp 4.2.3 Daten anhängen
    gp 4.2.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen
  gp 4.3 Vergleiche von Zeichenketten als String und StringBuffer
    gp 4.3.1 Sollte es ein equals() und hash() bei StringBuffer geben?
  gp 4.4 Ein paar kleine Helfer
    gp 4.4.1 Strings einer gegebenen Länge erzeugen und rechtsbündig ausgeben
    gp 4.4.2 Teile im String ersetzen
  gp 4.5 Zeichenkodierungen umwandeln
  gp 4.6 Sprachabhängiges Vergleichen mit der Collator-Klasse
    gp 4.6.1 Effiziente interne Speicherung für die Sortierung
  gp 4.7 Die Klasse StringTokenizer
  gp 4.8 StreamTokenizer
  gp 4.9 Formatieren mit Format-Objekten
    gp 4.9.1 Prozente, Zahlen und Währungen ausgeben
    gp 4.9.2 Ausgaben formatieren
    gp 4.9.3 Dezimalzahlformatierung
  gp 4.10 Reguläre Ausdrücke
    gp 4.10.1 Splitten von Zeichenketten
    gp 4.10.2 split() in String
    gp 4.10.3 Das Paket gnu.regexp
  gp 4.11 Überprüfung der E-Mail-Adressen und Kreditkarteninformationen
    gp 4.11.1 Gültige E-Mail-Adressen
    gp 4.11.2 Kreditkartennummern testen


Galileo Computing

4.8 StreamTokenizer  toptop

Die Klasse StreamTokenizer aus dem io-Paket arbeitet noch spezialisierter als die StringTokenizer-Klasse aus dem util-Paket. Im Gegensatz zum Tokenizer arbeitet ein StreamTokenizer nicht auf Strings, sondern auf einem Datenstrom, genauer gesagt, einem Reader. Damit greifen wir schon einmal ein Stückchen in Richtung Datenverarbeitung vor.

Während des Parsens werden bestimmte Merkmale aus dem Text erkannt, so unter anderem Bezeichner (etwa Schlüsselworte), Zahlen, Strings in Anführungszeichen und verschiedene Kommentararten (C-Stil oder C++-Stil). Verschiedene Java Tools von Sun verwenden intern einen StreamTokenizer, um ihre Eingabedateien zu verarbeiten, etwa das Policy-Tool für die Rechteverwaltung. Der Erkennungsvorgang wird anhand einer Syntaxtabelle überprüft. Diese Tabelle enthält zum Beispiel die Zeichen, die ein Schlüsselwort identifizieren, oder die Zeichen, die Trennzeichen sind. Jedes gelesene Zeichen wird dann keinem, einem oder mehreren Attributen zugeordnet. Diese Attribute fallen in die Kategorie Trennzeichen, alphanumerische Zeichen, Zahlen, Hochkomma- beziehungsweise Anführungszeichen oder Kommentarzeichen.

Zur Benutzung der Klasse wird zunächst ein StreamTokenizer-Objekt erzeugt und dann werden die Syntaxtabellen initialisiert. Ob Kommentarzeilen überlesen werden sollen, wird durch

st.slashSlashComments( true );       // Kommentar
st.slashStarComments( true );        /* Kommentar */

gesteuert. Die erste Methode überliest im Eingabestrom alle Zeichen bis zum Return. Die zweite Methode überliest nur alles bis zum Stern/Slash. Geschachtelte Kommentare sind hier nicht möglich.

Beim Lesen des Datenstroms mit nextToken() kann über bestimmte Flags erfragt werden, ob im Stream ein Wort beziehungsweise Bezeichner (TT_WORD), eine Zahl (TT_NUMBER), das Ende der Datei (TT_EOF) oder das Ende der Zeile (TT_EOL) vorliegt. Wichtig ist, eolIsSignificant(true) zu setzen, da andernfalls der StreamTokenizer nie ein TT_EOL findet. Wurde ein Wort erkannt, dann werden alle Zeichen in Kleinbuchstaben konvertiert. Dies lässt sich über die Methode lowerCaseMode(boolean) einstellen. Nach der Initialisierung eines StreamTokenizer-Objekts wird normalerweise so lange nextToken() aufgerufen, bis die Eingabe keine neuen Zeichen mehr hergibt, also ein TT_EOF-Token erkannt wurde.

Beispiel   Die folgende Klasse liest die Eingabe aus einer Datei und gibt die erkannten Textteile aus.

Listing 4.4   StreamTokenizerDemo.java

import java.io.*;

class StreamTokenizerDemo
{
  public static void main( String args[] ) throws IOException
  {
    String fn = "StreamTokenizerDemo.java";

    StreamTokenizer st = new StreamTokenizer(new FileReader(fn) );

//     st.slashSlashComments( true );
    st.slashStarComments( true );
    st.ordinaryChar( '/' );
    st.parseNumbers();
    st.eolIsSignificant( true );

    int tval;

    while ( ( tval=st.nextToken() ) != st.TT_EOF )
    {
      if ( tval == st.TT_NUMBER )
        System.out.println( "Nummer: " + st.nval );

      else if ( tval == st.TT_WORD )
        System.out.println( "Wort: " + st.sval );

      else if ( tval == st.TT_EOL )
        System.out.println( "Ende der Zeile" );

      else
        System.out.println( "Zeichen: " + (char) st.ttype );
    }
  }
}

Die Ausgabe des Programms beginnt wie folgt:

Zeichen: /
Zeichen: /
Wort: Version
Nummer: 1.1 
Ende der Zeile
Ende der Zeile
Wort: import
Wort: java.io.
Zeichen: *
Zeichen: ;
Ende der Zeile
Ende der Zeile
Wort: class
Wort: StreamTokenizerDemo
Ende der Zeile
Zeichen: {
Ende der Zeile
Wort: public

gp  StreamTokenizer( Reader r )
Erzeugt einen Tokenizer, der den Datenstrom zerlegt. Der Konstruktor, der das Ganze auch mit einem InputStream macht, ist veraltet.
gp  void resetSyntax()
Reinitialisiert die Syntaxtabelle des Tokenizers, sodass kein Zeichen eine Sonderbehandlung genießt. Mit ordinaryChar() lässt sich das Verhalten eines Zeichen bestimmen.
gp  void wordChars( int low, int hi )
Zeichen im Bereich von low <= c <= high werden als Bestandteile von Wörtern erkannt, dementsprechend zusammengefasst und als Word-Token übergeben.
gp  void whitespaceChars( int low, int hi )
Zeichen im Bereich von low <= c <= high werden als Trennzeichen erkannt.
gp  void ordinaryChars( int low, int hi )
Zeichen im Bereich von low <= c <= high genießen keine Sonderbehandlung und werden als normale Zeichen einzeln behandelt.
gp  void ordinaryChar( int ch )
Das Zeichen besitzt keine zusätzliche Funktion, ist zum Beispiel kein Kommentarzeichen, Trennsymbol oder Nummernzeichen. Spezialform für ordinaryChars(ch, ch).
gp  void parseNumbers()
Zahlen (Zahl-Literale) sollen vom Tokenizer erkannt werden. In der Syntaxtabelle gelten die zwölf Zeichen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ., – als numerisch. Liegt eine Ganz- oder Fließkommazahl vor, so wird der Zahlenwert in nval abgelegt und das Token ergibt im Attribut ttype den Wert TT_NUMBER.
gp  void commentChar( int ch )
Gibt das Zeichen an, welches einen einzeiligen Kommentar einleitet. Alle nachfolgenden Zeichen werden dann bis zum Zeilenende ignoriert. So ließen sich beispielsweise FORTRAN-Kommentare nach commentChar( 'C' ) überlesen.
gp  void slashStarComments( boolean flag )
Der Tokenizer soll Kommentare im C-Stil (/* Müll */) erkennen oder nicht.
gp  void slashSlashComments( boolean flag )
Der Tokenizer soll Kommentare im C++-Stil (// Zeile ) erkennen oder nicht.
gp  void lowerCaseMode( boolean fl )
Liegt in ttype ein Token vom Typ TT_WORD vor, so wird dies automatisch in Kleinschreibweise konvertiert, falls fl gleich true ist.
gp  int nextToken() throws IOException
Liefert das nächste Token im Datenstrom. Der Typ des Tokens wird im Attribut ttype hinterlegt. Zusätzliche Informationen befinden sich im Attribut nval (Nummer) oder sval (Zeichenkette). In der Regel wird so lange geparst, bis das Token TT_EOF zurückgegeben wird.
gp  void pushBack()
Legt das aktuelle Token in den Eingabestrom zurück. Ein Aufruf von nextToken() liefert erneut den aktuellen Wert im Attribut ttype und ändert nval oder sval nicht.
gp  int lineno()
Liefert die aktuelle Zeilennummer in der Eingabedatei.

Konsoleneingaben über StreamTokenizer einlesen

Da der StreamTokenizer mit nextToken() Zeichenketten liefert, können wir ihn mit dem Standardeingabestrom des Betriebssystems System.in initialisieren und anschließend von der Konsole in dem Attribut in.sval eingegebene Strings auslesen. So lassen sich Eingaben einfach verarbeiten.

StreamTokenizer in = new StreamTokenizer( System.in );
System.out.print( "Wie heißt du? ");
in.nextToken();
System.out.println( "Hallo " + in.sval );

Erweitern und Schwächen

Obwohl die nextToken()-Funktion eine ganze Menge an Konvertierungen durchführt, erkennt sie keine in der Exponentialdarstellung geschriebenen Zahlen. Bei einer Gleitkommazahl wie -31.415E-1 versagt die Konvertierung und liefert nur -31.415 als Token vom Typ TT_NUMBER. Da StreamTokenizer nicht final ist, kann jedoch jeder die Klasse so erweitern, dass sie zum Beispiel TT_FLOAT_NUMBER bei einer Gleitkommazahl liefert.






1   Die Klasse InputStream sollte nicht mehr verwendet werden, da diese nur auf Bytes und nicht auf Unicode-Zeichen arbeitet. Doch beachtet ein StreamTokenizer sowieso keine Unicode-Eingabe, sondern nur Zeichen aus dem Bereich von \u0000 bis \u00FF.





Copyright © Galileo Press GmbH 2003
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de