Skip to content

4. Häufig verwendete Klassen in Java

In diesem Kapitel stellen wir eine Reihe häufig verwendeter Java-Klassen vor. Diese verfügen über zahlreiche Attribute, Methoden und Konstruktoren. In jedem Fall präsentieren wir nur einen kleinen Ausschnitt der Klassen. Details dazu finden Sie in der Java-Hilfe, die wir nun vorstellen.

4.1. Die Dokumentation

Wenn Sie das Sun JDK im Ordner <jdk> installiert haben, finden Sie die Dokumentation im Ordner <jdk>\docs:

Image

Manchmal haben Sie zwar ein JDK, aber keine Dokumentation. Diese finden Sie auf der Website von Sun unter http://www.sun.com. Im Ordner „docs“ finden Sie eine Datei namens „index.html“, die als Einstiegspunkt für die JDK-Hilfe dient:

Image

Image

Über den Link „API & Language“ oben gelangt man zu den Java-Klassen. Der Link „Demos/Tutorials“ ist besonders nützlich, um Beispiele für Java-Programme zu finden. Folgen wir dem Link „API & Language“:

Image

Folgen wir dem Link zur Java 2 Platform API:

Image

Diese Seite ist der eigentliche Ausgangspunkt für die Klassendokumentation. Sie können eine Verknüpfung dazu erstellen, um schnell darauf zugreifen zu können. Die URL lautet <jdk>\docs\api\index.html. Sie enthält Links zu Hunderten von Java-Klassen im JDK. Wenn Sie gerade erst anfangen, besteht die größte Herausforderung darin, herauszufinden, was diese verschiedenen Klassen bewirken. Zu Beginn ist diese Ressource nur dann nützlich, wenn Sie den Namen der Klasse kennen, über die Sie Informationen suchen. Sie können sich auch an den Klassennamen orientieren, da diese in der Regel den Zweck der Klasse andeuten.

Nehmen wir ein Beispiel und suchen wir nach Informationen zur Vector-Klasse, die ein dynamisches Array implementiert. Suchen Sie einfach in der Klassenliste im linken Bereich nach dem Link zur Vector-Klasse:

Image

und klicken Sie auf den Link, um die Klassendefinition anzuzeigen:

Image

Dort finden Sie

  • die Hierarchie, in der sich die Klasse befindet, in diesem Fall java.util.Vector
  • die Liste der Felder (Attribute) der Klasse
  • die Liste der Konstruktoren
  • die Liste der Methoden

In den folgenden Abschnitten stellen wir verschiedene Klassen vor. Wir empfehlen dem Leser, die vollständige Definition der verwendeten Klassen systematisch zu überprüfen.

4.2. Testklassen

In den folgenden Beispielen werden teilweise die Klassen „Person“ und „Teacher“ verwendet. Ihre Definitionen finden Sie hier.

public class personne{
    // last name, first name, age
  private String prenom;
  private String nom;
  private int age;

  // builder 1
  public personne(String P, String N, int age){
    this.prenom=P;
    this.nom=N;
    this.age=age;
  }

   // builder 2
  public personne(personne P){
    this.prenom=P.prenom;
    this.nom=P.nom;
    this.age=P.age;
  }

  // toString
  public String toString(){
    return "personne("+prenom+","+nom+","+age+")";
  }

  // accessors
  public String getPrenom(){
    return prenom;
  }
  public String getNom(){
    return nom;
  }
  public int getAge(){
    return age;
  }

  //modifiers
  public void setPrenom(String P){
    this.prenom=P;
  }
  public void setNom(String N){
    this.nom=N;
  }
  public void setAge(int age){
    this.age=age;
  }
}

Die Klasse „Teacher“ ist von der Klasse „Person“ abgeleitet und wie folgt definiert:

class enseignant extends personne{
// attributes
  private int section;

    // manufacturer
  public enseignant(String P, String N, int age,int section){
    super(P,N,age);
    this.section=section;
  }
    // toString
  public String toString(){
    return "etudiant("+super.toString()+","+section+")";    
  }
}

Wir werden außerdem eine Klasse „Student“ verwenden, die von der Klasse „Person“ abgeleitet und wie folgt definiert ist:


class etudiant extends personne{
  String numero;
 
  public etudiant(String P, String N, int age,String numero){
    super(P,N,age);
    this.numero=numero;
  }
 
  public String toString(){
    return "etudiant("+super.toString()+","+numero+")";    
  }    
}

4.3. Die String-Klasse

Die String-Klasse repräsentiert Zeichenfolgen. Sei *name* eine Zeichenfolgenvariable:

*String name;*

name ist eine Referenz auf ein Objekt, das noch nicht initialisiert wurde. Es kann auf zwei Arten initialisiert werden:

**name = &quot;Pferd&quot;** oder **name = new String(&quot;Pferd&quot;)**

Beide Methoden sind gleichwertig. Wenn wir später name=&quot;fish&quot; schreiben, verweist name dann auf ein neues Objekt. Das alte String(&quot;horse&quot;)-Objekt geht verloren, und der von ihm belegte Speicher wird freigegeben.

Die Klasse String verfügt über viele Attribute und Methoden. Hier sind einige davon:

public char charAt(int i)
gibt das Zeichen an Position i in der Zeichenkette zurück, wobei das erste Zeichen die Position 0 hat. Somit ist `String("horse").charAt(3)` gleich 'h'
public int compareTo(string2)
string1.compareTo(string2) vergleicht string1 mit string2 und gibt 0 zurück, wenn string1 = string2, 1, wenn string1 > string2, und -1, wenn string1 < string2
public boolean equals(Object anObject)
string1.equals(string2) gibt true zurück, wenn string1 = string2 ist, andernfalls false
public String toLowerCase()
string1.toLowerCase() wandelt string1 in Kleinbuchstaben um
public String toUpperCase()
string1.toUpperCase() wandelt string1 in Großbuchstaben um
public String trim()
string1.trim() entfernt führende und nachgestellte Leerzeichen aus string1
public String substring(int beginIndex, int endIndex)
String("chapeau").subString(2,4) gibt die Zeichenfolge "ape" zurück
public char[] toCharArray()
konvertiert die Zeichen der Zeichenkette in ein Zeichenarray
int length()
Anzahl der Zeichen in der Zeichenkette
int indexOf(String string2)
gibt die erste Stelle zurück, an der string2 in der aktuellen Zeichenkette vorkommt, oder -1, wenn string2 nicht vorhanden ist
int indexOf(String string2, int startIndex)
Gibt die erste Stelle zurück, an der string2 in der aktuellen Zeichenkette vorkommt, oder -1, wenn string2 nicht gefunden wird. Die Suche beginnt bei dem Zeichen an der Position startIndex.
int lastIndexOf(String string2)
Gibt die letzte Position von string2 im aktuellen String zurück oder -1, wenn string2 nicht vorhanden ist
boolean startsWith(String string2)
gibt true zurück, wenn die aktuelle Zeichenkette mit string2 beginnt
boolean endsWith(String string2)
gibt „true“ zurück, wenn die aktuelle Zeichenfolge mit string2 endet
boolean matches(String regex)
gibt true zurück, wenn die aktuelle Zeichenfolge mit dem regulären Ausdruck regex übereinstimmt.
String[] split(String regex)
Die aktuelle Zeichenfolge besteht aus Feldern, die durch eine Zeichenfolge getrennt sind, die dem regulären Ausdruck regex entspricht. Die Methode split ruft die Felder in ein Array ab.
String replace(char oldChar, char newChar)
Ersetzt das Zeichen oldChar im aktuellen String durch das Zeichen newChar.

Hier ist ein Beispielprogramm:

// imports
import java.io.*;

public class string1{
    // a demonstration class
    public static void main(String[] args){
        String uneChaine="l'oiseau vole au-dessus des nuages";
        affiche("uneChaine="+uneChaine);
        affiche("uneChaine.Length="+uneChaine.length());
        affiche("chaine[10]="+uneChaine.charAt(10));
        affiche("uneChaine.IndexOf(\"vole\")="+uneChaine.indexOf("vole"));
        affiche("uneChaine.IndexOf(\"x\")="+uneChaine.indexOf("x"));
        affiche("uneChaine.LastIndexOf('a')="+uneChaine.lastIndexOf('a'));
        affiche("uneChaine.LastIndexOf('x')="+uneChaine.lastIndexOf('x'));
        affiche("uneChaine.substring(4,7)="+uneChaine.substring(4,7));
        affiche("uneChaine.ToUpper()="+uneChaine.toUpperCase());
        affiche("uneChaine.ToLower()="+uneChaine.toLowerCase());
        affiche("uneChaine.Replace('a','A')="+uneChaine.replace('a','A'));
        String[] champs=uneChaine.split("\\s+");
        for (int i=0;i<champs.length;i++){
            affiche("champs["+i+"]=["+champs[i]+"]");
        }//for
        affiche("(\"  abc  \").trim()=["+"  abc  ".trim()+"]");
    }//Main

  // poster
    public static void affiche(String msg){
        // poster msg
        System.out.println(msg);
    }//poster
}//class

und die erhaltenen Ergebnisse:

uneChaine=l'oiseau vole au-dessus des nuages
uneChaine.Length=34
chaine[10]=o
uneChaine.IndexOf("vole")=9
uneChaine.IndexOf("x")=-1
uneChaine.LastIndexOf('a')=30
uneChaine.LastIndexOf('x')=-1
uneChaine.substring(4,7)=sea
uneChaine.ToUpper()=L'OISEAU VOLE AU-DESSUS DES NUAGES
uneChaine.ToLower()=l'oiseau vole au-dessus des nuages
uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges
champs[0]=[l'oiseau]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
("  abc  ").trim()=[abc]

4.4. Die Vektorklasse

Ein Vektor ist ein dynamisches Array, dessen Elemente Objektreferenzen sind. Es handelt sich also um ein Array von Objekten, dessen Größe sich im Laufe der Zeit ändern kann, was bei den statischen Arrays, die wir bisher kennengelernt haben, nicht möglich ist. Hier sind einige Felder, Konstruktoren oder Methoden dieser Klasse:

public Vector()
erstellt einen leeren Vektor
public final int size()
Anzahl der Elemente im Vektor
public final void addElement(Object obj)
fügt das durch obj referenzierte Objekt zum Vektor hinzu
public final Object elementAt(int index)
Verweis auf das Objekt an der Position index im Array – Indizes beginnen bei 0
public final Enumeration elements()
die Menge der Elemente im Array als Enumeration
public final Object firstElement()
Verweis auf das erste Element des Arrays
public final Object lastElement()
Verweis auf das letzte Element des Vektors
public final boolean isEmpty()
gibt „true“ zurück, wenn das Array leer ist
public final void removeElementAt(int index)
entfernt das Element an der Position index
public final void removeAllElements()
löscht alle Elemente aus dem Array
public final String toString()
gibt eine Zeichenkette zurück, die das Array darstellt

Hier ist ein Testprogramm:


// imported classes
import java.util.*;
 
public class test1{
 
// main program - static - class method
 
  public static void main(String arg[]){
 
// creation of objects that are instances of classes
    personne p=new personne("Jean","Dupont",30);
    enseignant en=new enseignant("Paula","Hanson",56,27);
    etudiant et=new etudiant("Chris","Garot",22,"19980405");
    System.out.println("p="+p.toString());
    System.out.println("en="+en.toString());
    System.out.println("et="+et.toString());
 
// polymorphism
    personne p2=(personne)en;
    System.out.println("p2="+p2.toString());
    personne p3=(personne)et;
    System.out.println("p3="+p3.toString());
 
// a vector
    Vector V=new Vector();
    V.addElement(p);V.addElement(en);V.addElement(et);
    System.out.println("Taille du vecteur V = "+V.size());
    for(int i=0;i<V.size();i++){
      p2=(personne) V.elementAt(i);
      System.out.println("V["+i+"]="+p2.toString());
    }
} // fine hand
}// end of class

Kompilieren wir dieses Programm:

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>dir
10/06/2002  10:41                1 134 personne.class
10/06/2002  10:41                  619 enseignant.class
10/06/2002  10:41                  610 etudiant.class
10/06/2002  10:42                1 035 test1.java
E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>javac test1.java

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>dir
10/06/2002  10:41                1 134 personne.class
10/06/2002  10:41                  619 enseignant.class
10/06/2002  10:41                  610 etudiant.class
10/06/2002  10:42                1 035 test1.java
10/06/2002  10:43                1 506 test1.class

Führen wir die Datei test1.class aus:

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\vector>java test1
p=personne(Jean,Dupont,30)
en=etudiant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=etudiant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
Taille du vecteur V = 3
V[0]=personne(Jean,Dupont,30)
V[1]=etudiant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)

Von nun an werden wir den Vorgang des Kompilierens und Ausführens der Testprogramme nicht mehr wiederholen. Wiederholen Sie einfach die oben beschriebenen Schritte.

4.5. Die ArrayList-Klasse

Die Klasse ArrayList entspricht der Klasse Vector. Sie unterscheidet sich von dieser im Wesentlichen nur dann, wenn sie von mehreren Threads gleichzeitig genutzt wird. Die Methoden zur Thread-Synchronisation für den Zugriff auf einen Vector oder eine ArrayList unterscheiden sich. Abgesehen davon können beide Klassen austauschbar verwendet werden. Hier sind einige Felder, Konstruktoren und Methoden dieser Klasse:

ArrayList()
erstellt ein leeres Array
int size()
Anzahl der Elemente im Array
void add(Object obj)
fügt das durch obj referenzierte Objekt zum Array hinzu
void add(int index, Object obj)
fügt das durch obj referenzierte Objekt an der Position index zum Array hinzu
Object get(int index)
Verweis auf das Objekt an der Position index im Array – Indizes beginnen bei 0
boolean isEmpty()
gibt „true“ zurück, wenn das Array leer ist
void remove(int index)
Entfernt das Element an der Position index
void clear()
löscht alle Elemente aus dem Array
Object[] toArray()
wandelt das dynamische Array in ein Standard-Array um
String toString()
gibt eine Zeichenkette zurück, die das Array darstellt

Hier ist ein Testprogramm:

// imported classes
import java.util.*;

public class test1{

// main program - static - class method

  public static void main(String arg[]){

// creation of objects that are instances of classes
    personne p=new personne("Jean","Dupont",30);
    enseignant en=new enseignant("Paula","Hanson",56,27);
    etudiant et=new etudiant("Chris","Garot",22,"19980405");
    System.out.println("p="+p);
    System.out.println("en="+en);
    System.out.println("et="+et);

// polymorphism
    personne p2=(personne)en;
    System.out.println("p2="+p2);
    personne p3=(personne)et;
    System.out.println("p3="+p3);

// a vector
    ArrayList personnes=new ArrayList();
    personnes.add(p);personnes.add(en);personnes.add(et);
    System.out.println("Nombre de personnes = "+personnes.size());
    for(int i=0;i<personnes.size();i++){
      p2=(personne) personnes.get(i);
      System.out.println("personnes["+i+"]="+p2);
    }
} // fine hand
}// end of class

Die erhaltenen Ergebnisse sind dieselben wie zuvor.

4.6. Die Arrays-Klasse

Die Klasse *java.util.Arrays* bietet Zugriff auf statische Methoden, mit denen verschiedene Operationen an Arrays durchgeführt werden können, insbesondere das Sortieren und Suchen von Elementen. Hier sind einige dieser Methoden:

static void sort(array)
sortiert das Array anhand der impliziten Reihenfolge des Datentyps des Arrays, unabhängig davon, ob es sich um Zahlen oder Zeichenfolgen handelt.
static void sort(Object[] array, Comparator C)
Sortiert das Array unter Verwendung der Vergleichsfunktion C zum Vergleichen der Elemente
static int binarySearch(array, element)
Gibt die Position des Elements im Array zurück oder andernfalls einen Wert <0. Das Array muss zuvor sortiert worden sein.
static int binarySearch(Object[] array, Object element, Comparator C)
Wie oben, verwendet jedoch die Vergleichsfunktion C, um zwei Elemente im Array zu vergleichen.

Hier ist ein erstes Beispiel:

import java.util.*;

public class sort2 implements Comparator{

   // an internal private class
  private class personne{
    private String nom;
    private int age;
    public personne(String nom, int age){
      this.nom=nom; // person's name
      this.age=age; // his age
    }
     // recover age
    public int getAge(){
      return age;
    }
     // identity of the person
    public String toString(){
      return ("["+nom+","+age+"]");
    }
  }; // class person

   // manufacturer
  public sort2() {
     // a table of people
    personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
        new personne("tournesol",40)};
     // sorting the people table
    Arrays.sort(amis,this);
     // check
    for(int i=0;i<3;i++)
      System.out.println(amis[i]);
  }//manufacturer

   // the function that compares people
  public int compare(Object o1, Object o2){
    // must make
     // -1 if o1 "smaller than" o2
     // 0 if o1 "equal to" o2
     // +1 if o1 "greater than" o2
    personne p1=(personne)o1;
    personne p2=(personne)o2;
    int age1=p1.getAge();
    int age2=p2.getAge();
    if(age1<age2) return (-1);
      else if (age1==age2) return (0);
        else return +1;
  }//compare

    // test function
  public static void main(String[] arg){
    new sort2();
  }//hand

}//class

Sehen wir uns dieses Programm einmal an. Die Hauptfunktion erstellt ein sort2-Objekt. Der Konstruktor für die Klasse sort2 sieht wie folgt aus:

   // manufacturer
  public sort2() {
     // a table of people
    personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
        new personne("tournesol",40)};
     // sorting the people table
    Arrays.sort(amis,this);
     // check
    for(int i=0;i<3;i++)
      System.out.println(amis[i]);
  }//manufacturer

Das zu sortierende Array ist ein Array von Person-Objekten. Die Person-Klasse ist innerhalb der sort2-Klasse als privat definiert. Die statische sort-Methode der Arrays-Klasse weiß nicht, wie ein Array von Person-Objekten sortiert wird, daher sind wir hier gezwungen, die Form void sort(Object[] obj, Comparator C) zu verwenden. Comparator ist eine Schnittstelle, die nur eine Methode definiert:

    int compare(Object o1, Object o2)

und die 0 zurückgeben muss, wenn o1=o2, -1, wenn o1 < o2, und +1, wenn o1 > o2. Im Prototyp void sort(Object[] obj, Comparator C) muss das zweite Argument C ein Objekt sein, das die Comparator-Schnittstelle implementiert. Im Konstruktor von sort2 haben wir das aktuelle Objekt this gewählt:

     // sorting the people table
    Arrays.sort(amis,this);

Dies erfordert zwei Maßnahmen:

  1. Angeben, dass die Klasse „sort2“ die Comparator-Schnittstelle implementiert
public class sort2 implements Comparator{
  1. die Vergleichsfunktion in der Klasse sort2 schreiben.

Dies sieht wie folgt aus:

   // the function that compares people
  public int compare(Object o1, Object o2){
    // must make
     // -1 if o1 "smaller than" o2
     // 0 if o1 "equal to" o2
     // +1 if o1 "greater than" o2
    personne p1=(personne)o1;
    personne p2=(personne)o2;
    int age1=p1.getAge();
    int age2=p2.getAge();
    if(age1<age2) return (-1);
      else if (age1==age2) return (0);
        else return +1;
  }//compare

Um zwei Person-Objekte zu vergleichen, verwenden wir hier das Alter (wir hätten auch den Namen verwenden können).

Die Ergebnisse der Ausführung lauten wie folgt:

[tournesol,40]
[milou,80]
[tintin,100]

Wir hätten bei der Implementierung der Comparator-Schnittstelle auch anders vorgehen können:

import java.util.*;

public class sort2 {

  // an internal private class
  private class personne{
…….
  }; // class person

   // manufacturer
  public sort2() {
     // a table of people
    personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
        new personne("tournesol",40)};
     // sorting the people table
    Arrays.sort(amis,
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare1(o1,o2);
        }//compare
      }//class
    );
     // check
    for(int i=0;i<3;i++)
      System.out.println(amis[i]);
  }//manufacturer

   // the function that compares people
  public int compare1(Object o1, Object o2){
    // must make
     // -1 if o1 "smaller than" o2
     // 0 if o1 "equal to" o2
     // +1 if o1 "greater than" o2
    personne p1=(personne)o1;
    personne p2=(personne)o2;
    int age1=p1.getAge();
    int age2=p2.getAge();
    if(age1<age2) return (-1);
      else if (age1==age2) return (0);
        else return +1;
  }//compare1

  // hand
  public static void main(String[] arg){
    new sort2();
  }//hand
}//class

Die Sortieranweisung lautet nun wie folgt:

     // sorting the people table
    Arrays.sort(amis,
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare1(o1,o2);
        }//compare
      }//class
    );

Der zweite Parameter der compare-Methode muss ein Objekt sein, das die Comparator-Schnittstelle implementiert. Hier erstellen wir ein solches Objekt mit new java.util.Comparator(), und der Text, der auf {…} folgt, definiert die Klasse, aus der das Objekt erstellt wird. Diese wird als anonyme Klasse bezeichnet, da sie keinen Namen hat. In dieser anonymen Klasse, die die Comparator-Schnittstelle implementieren muss, definieren wir die compare-Methode dieser Schnittstelle. Diese Methode ruft einfach die compare1-Methode der sort2-Klasse auf. Damit sind wir wieder beim vorherigen Fall angelangt.

Die Klasse sort2 implementiert die Comparator-Schnittstelle nicht mehr. Daher lautet ihre Deklaration nun:

public class sort2 {

Nun testen wir die Methode binarySearch der Klasse *Arrays* anhand des folgenden Beispiels:

import java.util.*;

public class sort4 {

  // an internal private class
  private class personne{
      // attributes
    private String nom;
    private int age;

        // manufacturer
    public personne(String nom, int age){
      this.nom=nom; // person's name
      this.age=age; // his age
    }

     // retrieve name
    public String getNom(){
      return nom;
    }

     // recover age
    public int getAge(){
      return age;
    }
     // identity of the person
    public String toString(){
      return ("["+nom+","+age+"]");
    }
  }; // class person

   // manufacturer
  public sort4() {
     // a table of people
    personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
        new personne("tournesol",40)};

     // comparators
    java.util.Comparator comparateur1=
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare1(o1,o2);
        }//compare
      }//class
      ;
    java.util.Comparator comparateur2=
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare2(o1,o2);
        }//compare
      }//class
      ;          

     // sorting the people table
    Arrays.sort(amis,comparateur1);
    // check
    for(int i=0;i<3;i++)
      System.out.println(amis[i]);
    // research
    cherche("milou",amis,comparateur2);
    cherche("xx",amis,comparateur2);
  }//manufacturer

   // the function that compares people
  public int compare1(Object o1, Object o2){
    // must make
     // -1 if o1 "smaller than" o2
     // 0 if o1 "equal to" o2
     // +1 if o1 "greater than" o2
    personne p1=(personne)o1;
    personne p2=(personne)o2;
    int age1=p1.getAge();
    int age2=p2.getAge();
    if(age1<age2) return (-1);
      else if (age1==age2) return (0);
        else return +1;
  }//compare1

   // the function that compares a person to a name
  public int compare2(Object o1, Object o2){
    // o1 is a person
     // o2 is a String, the name name2 of a person
     // must make
     // -1 if o1.nom "smaller than" name2
     // 0 if o1.nom "equal to" name2
     // +1 if o1.nom "greater than" name2
    personne p1=(personne)o1;
    String nom1=p1.getNom();
    String nom2=(String)o2;
    return nom1.compareTo(nom2);
  }//compare2

    public void cherche(String ami,personne[] amis, Comparator comparateur){
       // search for a friend in the friends table
    int position=Arrays.binarySearch(amis,ami,comparateur);
     // found?
    if(position>=0)
        System.out.println(ami + " a " + amis[position].getAge() + " ans");
    else System.out.println(ami + " n'existe pas dans le tableau");
  }//search

  // hand
  public static void main(String[] arg){
    new sort4();
  }//hand
}//class

Hier sind wir etwas anders vorgegangen als in den vorherigen Beispielen. Die beiden Comparator-Objekte, die von den Methoden sort und binarySearch benötigt werden, wurden erstellt und den Variablen comparator1 und comparator2 zugewiesen.

     // comparators
    java.util.Comparator comparateur1=
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare1(o1,o2);
        }//compare
      }//class
      ;
    java.util.Comparator comparateur2=
        new java.util.Comparator(){
          public int compare(Object o1, Object o2){
            return compare2(o1,o2);
        }//compare
      }//class
      ;          

Im Konstruktor sort4 wird zweimal eine binäre Suche im Array „friends“ durchgeführt:

    // recherches
    cherche("milou",amis,comparateur2);
    cherche("xx",amis,comparateur2);

Die Suchmethode erhält alle Parameter, die sie benötigt, um die Methode binarySearch aufzurufen:

    public void cherche(String ami,personne[] amis, Comparator comparateur){
       // search for a friend in the friends table
    int position=Arrays.binarySearch(amis,ami,comparateur);
     // found?
    if(position>=0)
        System.out.println(ami + " a " + amis[position].getAge() + " ans");
    else System.out.println(ami + " n'existe pas dans le tableau");
  }//search

Die Methode binarySearch arbeitet mit dem Komparator comparator2, der wiederum die Methode compare2* der Klasse sort4 aufruft. Die Methode gibt die Position des gesuchten Namens im Array zurück, falls dieser vorhanden ist, andernfalls eine Zahl <0. Die Methode compare2 wird verwendet, um ein Person-Objekt mit einem Namen vom Typ String* zu vergleichen.

   // the function that compares a person to a name
  public int compare2(Object o1, Object o2){
    // o1 is a person
     // o2 is a String, the name name2 of a person
     // must make
     // -1 if o1.nom "smaller than" name2
     // 0 if o1.nom "equal to" name2
     // +1 if o1.nom "greater than" name2
    personne p1=(personne)o1;
    String nom1=p1.getNom();
    String nom2=(String)o2;
    return nom1.compareTo(nom2);
  }//compare2

Im Gegensatz zur sort-Methode nimmt die binarySearch-Methode nicht zwei Person-Objekte entgegen, sondern ein Person-Objekt und ein String-Objekt in dieser Reihenfolge. Der erste Parameter ist ein Element des friends-Arrays, der zweite ist der Name der gesuchten Person.

4.7. Die Klasse „Enumeration“

Enumeration ist eine Schnittstelle, keine Klasse. Sie verfügt über die folgenden Methoden:

public abstract boolean hasMoreElements()
gibt „true“ zurück, wenn die Enumeration noch Elemente enthält
public abstract Object nextElement()
gibt eine Referenz auf das nächste Element in der Enumeration zurück

Wie verwendet man eine Enumeration? Im Allgemeinen so:

    Enumeration e=                // an enumeration object is retrieved
    while(e.hasMoreElements()){
        // use e.nextElement() element
    }

Hier ist ein Beispiel:


// imported classes
import java.util.*;
 
public class test1{
 
// main program - static - class method
 
  public static void main(String arg[]){
 
// creation of objects that are instances of classes
    personne p=new personne("Jean","Dupont",30);
    enseignant en=new enseignant("Paula","Hanson",56,27);
    etudiant et=new etudiant("Chris","Garot",22,"19980405");
    System.out.println("p="+p.toString());
    System.out.println("en="+en.toString());
    System.out.println("et="+et.toString());
 
// polymorphism
    personne p2=(personne)en;
    System.out.println("p2="+p2.toString());
    personne p3=(personne)et;
    System.out.println("p3="+p3.toString());
 
// a vector
    Vector V=new Vector();
    V.addElement(p);V.addElement(en);V.addElement(et);
    System.out.println("Taille du vecteur V = "+V.size());
    int i;
    for(i=0;i<V.size();i++){
      p2=(personne) V.elementAt(i);
      System.out.println("V["+i+"]="+p2.toString());
    }
 
// an enumeration
    Enumeration E=V.elements();
    i=0;
    while(E.hasMoreElements()){
      p2=(personne) E.nextElement();
      System.out.println("V["+i+"]="+p2.toString());
      i++;
    }
   }// fine hand
}//end of class

Es werden folgende Ergebnisse erhalten:

p=personne(Jean,Dupont,30)
en=enseignant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=enseignant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
Taille du vecteur V = 3
V[0]=personne(Jean,Dupont,30)
V[1]=enseignant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)
V[0]=personne(Jean,Dupont,30)
V[1]=enseignant(personne(Paula,Hanson,56),27)
V[2]=etudiant(personne(Chris,Garot,22),19980405)

4.8. Die HashTable-Klasse

Mit der HashTable-Klasse können Sie ein Wörterbuch implementieren. Ein Wörterbuch kann als zweispaltiges Array betrachtet werden:

Schlüssel
Wert
Schlüssel1
Wert1
Schlüssel2
Wert2
..
...

Schlüssel sind eindeutig, d. h., es kann keine zwei identischen Schlüssel geben. Die wichtigsten Methoden und Eigenschaften der Hashtable-Klasse sind wie folgt:

public Hashtable()
Konstruktor – erstellt ein leeres Wörterbuch
public int size()
Anzahl der Elemente im Wörterbuch – wobei ein Element ein Paar (Schlüssel, Wert) ist
public Object put(Object key, Object value)
fügt das Paar (Schlüssel, Wert) zum Wörterbuch hinzu
public Object get(Object key)
Ruft das mit dem Schlüssel „key“ verknüpfte Objekt ab oder gibt „null“ zurück, falls der Schlüssel „key“ nicht existiert
public boolean containsKey(Object key)
true, wenn der Schlüssel im Wörterbuch vorhanden ist
public boolean contains(Object value)
true, wenn der Wert value im Wörterbuch vorhanden ist
public Enumeration keys()
gibt die Schlüssel des Wörterbuchs als Aufzählung zurück
public Object remove(Object key)
entfernt das (Schlüssel, Wert)-Paar, wobei Schlüssel=Schlüssel
public String toString()
identifiziert das Wörterbuch

Hier ist ein Beispiel:


// imported classes
import java.util.*;
 
public class test1{
 
// main program - static - class method
 
  public static void main(String arg[]){
 
// creation of objects that are instances of classes
    personne p=new personne("Jean","Dupont",30);
    enseignant en=new enseignant("Paula","Hanson",56,27);
    etudiant et=new etudiant("Chris","Garot",22,"19980405");
    System.out.println("p="+p.toString());
    System.out.println("en="+en.toString());
    System.out.println("et="+et.toString());
 
// polymorphism
    personne p2=(personne)en;
    System.out.println("p2="+p2.toString());
    personne p3=(personne)et;
    System.out.println("p3="+p3.toString());

// a dictionary
    Hashtable H=new Hashtable();
    H.put("personne1",p);
    H.put("personne2",en);
    H.put("personne3",et);
    Enumeration E=H.keys();
    int i=0;
    String cle;
    while(E.hasMoreElements()){
      cle=(String) E.nextElement();
      p2=(personne) H.get(cle);
      System.out.println("clé "+i+"="+cle+" valeur="+p2.toString());
      i++;
    }
  }//fine hand
}//end of class

Die Ergebnisse lauten wie folgt:

p=personne(Jean,Dupont,30)
en=enseignant(personne(Paula,Hanson,56),27)
et=etudiant(personne(Chris,Garot,22),19980405)
p2=enseignant(personne(Paula,Hanson,56),27)
p3=etudiant(personne(Chris,Garot,22),19980405)
clé 0=personne3 valeur=etudiant(personne(Chris,Garot,22),19980405)
clé 1=personne2 valeur=enseignant(personne(Paula,Hanson,56),27)
clé 2=personne1 valeur=personne(Jean,Dupont,30)

4.9. Textdateien

4.9.1. Schreiben

Um in eine Datei zu schreiben, benötigen Sie einen Schreibstrom. Hierfür können Sie die Klasse FileWriter verwenden. Die folgenden Konstruktoren werden häufig verwendet:

FileWriter(String fileName)
erstellt eine Datei mit dem Namen fileName – Sie können dann in diese schreiben – jede bereits vorhandene Datei mit demselben Namen wird überschrieben
FileWriter(String fileName,
boolean append)
wie oben – jede vorhandene Datei mit demselben Namen kann verwendet werden, indem sie im Anfüge-Modus geöffnet wird (append=true)

Die Klasse FileWriter bietet eine Reihe von Methoden zum Schreiben in eine Datei, die von der Klasse Writer geerbt wurden. Zum Schreiben in eine Textdatei empfiehlt sich die Verwendung der Klasse PrintWriter, deren häufig verwendete Konstruktoren wie folgt lauten:

PrintWriter(Writer out)
Das Argument ist vom Typ Writer, d. h. ein Schreibstrom (in eine Datei, über das Netzwerk usw.)
PrintWriter(Writer out, boolean autoflush)
Wie oben. Das zweite Argument steuert die Zeilenpufferung. Bei der Einstellung „false“ (Standard) durchlaufen die in die Datei geschriebenen Zeilen einen Puffer im Arbeitsspeicher. Wenn der Puffer voll ist, wird er in die Datei geschrieben. Dies verbessert den Festplattenzugriff. Allerdings ist dieses Verhalten manchmal unerwünscht, insbesondere beim Schreiben über ein Netzwerk.

Die nützlichen Methoden der PrintWriter-Klasse sind wie folgt:

void print(Type T)
schreibt die Daten T (String, int, …)
void println(Type T)
wie oben, endet jedoch mit einem Zeilenumbruchzeichen
void flush()
leert den Puffer, wenn nicht im Autoflush-Modus
void close()
schließt den Schreibstrom

Hier ist ein Programm, das einige Zeilen in eine Textdatei schreibt:

// imports
import java.io.*;

public class ecrire{
  public static void main(String[] arg){
    // open file
    PrintWriter fic=null;
    try{
      fic=new PrintWriter(new FileWriter("out"));
    } catch (Exception e){
      Erreur(e,1);
    }
     // write to file
    try{
      fic.println("Jean,Dupont,27");
      fic.println("Pauline,Garcia,24");
      fic.println("Gilles,Dumond,56");
    } catch (Exception e){
      Erreur(e,3);
    }
     // close file
    try{
      fic.close();
    } catch (Exception e){
      Erreur(e,2);
    }
  }// fine hand

  private static void Erreur(Exception e, int code){
    System.err.println("Erreur : "+e);
    System.exit(code);
  }//Error
}//class

Die vom Programm erzeugte Ausgabedatei sieht wie folgt aus:

Jean,Dupont,27
Pauline,Garcia,24
Gilles,Dumond,56

4.9.2. Lesen

Um den Inhalt einer Datei zu lesen, benötigen Sie einen mit der Datei verknüpften Lesestrom. Dazu können Sie die Klasse FileReader und den folgenden Konstruktor verwenden:

FileReader(String filename)
öffnet einen Lesestrom aus der angegebenen Datei. Löst eine Ausnahme aus, wenn der Vorgang fehlschlägt.

Die Klasse FileReader verfügt über eine Reihe von Methoden zum Lesen aus einer Datei, die von der Klasse Reader geerbt wurden. Um Textzeilen aus einer Textdatei zu lesen, empfiehlt es sich, die Klasse BufferedReader mit dem folgenden Konstruktor zu verwenden:

BufferedReader(Reader in)
öffnet einen gepufferten Lesestrom aus einem Eingabestrom in. Dieser Strom vom Typ Reader kann von der Tastatur, einer Datei, dem Netzwerk usw. stammen.

Die nützlichen Methoden der BufferedReader-Klasse sind wie folgt:

int read()
liest ein Zeichen
String readLine()
liest eine Textzeile
int read(char[] buffer, int offset, int size)
Liest „size“ Zeichen aus der Datei und speichert sie ab der Position „offset“ im Pufferarray.
void close()
schließt den Lesestrom

Hier ist ein Programm, das den Inhalt der zuvor erstellten Datei liest:

// imported classes
import java.util.*;
import java.io.*;

public class lire{
  public static void main(String[] arg){
    personne p=null;
     // open file
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new FileReader("out"));
    } catch (Exception e){
      Erreur(e,1);
    }
     // data
    String ligne=null;
    String[] champs=null;
    String prenom=null;
    String nom=null;
    int age=0;

    // error handling
    try{
      while((ligne=IN.readLine())!=null){
        champs=ligne.split(",");
        prenom=champs[0];
        nom=champs[1];
        age=Integer.parseInt(champs[2]);
        System.out.println(""+new personne(prenom,nom,age));
      }// end while
    } catch (Exception e){
      Erreur(e,2);
    }

     // close file
    try{
      IN.close();
    } catch (Exception e){
      Erreur(e,3);
    }
  }// fine hand

   // Error
  public static void Erreur(Exception e, int code){
    System.err.println("Erreur : "+e);
    System.exit(code);
  }

}// end of class

Die Ausführung des Programms liefert folgende Ergebnisse:

personne(Jean,Dupont,27)
personne(Pauline,Garcia,24)
personne(Gilles,Dumond,56)

4.9.3. Speichern eines Personenobjekts

Wir wenden das soeben Gesehene an, um die Klasse „Person“ um eine Methode zu erweitern, mit der wir die Attribute einer Person in einer Datei speichern können. Wir fügen die Methode „saveAttributes“ zur Definition der Klasse „Person“ hinzu:


    // ------------------------------
  // sauvegarde dans fichier texte
    // ------------------------------
  public void sauveAttributs(PrintWriter P){
    P.println(""+this);
  }

Vergessen Sie nicht, vor der Definition der Klasse „Person“ das Paket „java.io“ zu importieren:

import java.io.*;

Die Methode „saveAttributes“ benötigt einen einzigen Parameter: den „PrintWriter“-Stream, in den sie schreiben soll. Ein Testprogramm könnte wie folgt aussehen:

// imports
import java.io.*;
// import nobody;

public class sauver{
  public static void main(String[] arg){
    // open file
    PrintWriter fic=null;
    try{
      fic=new PrintWriter(new FileWriter("out"));
    } catch (Exception e){
      Erreur(e,1);
    }
     // write to file
    try{
      new personne("Jean","Dupont",27).sauveAttributs(fic);
      new personne("Pauline","Garcia",24).sauveAttributs(fic);
      new personne("Gilles","Dumond",56).sauveAttributs(fic);
    } catch (Exception e){
      Erreur(e,3);
    }
     // close file
    try{
      fic.close();
    } catch (Exception e){
      Erreur(e,2);
    }
  }// fine hand

   // Error
  private static void Erreur(Exception e, int code){
    System.err.println("Erreur : "+e);
    System.exit(code);
  }//Error
}//class

Kompilieren und führen wir dieses Programm aus:

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>javac sauver.java

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>dir
10/06/2002  10:52                1 352 personne.class
10/06/2002  10:53                  842 sauver.java
10/06/2002  10:53                1 258 sauver.class

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>java sauver

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>dir
10/06/2002  10:52                1 352 personne.class
10/06/2002  10:53                  842 sauver.java
10/06/2002  10:53                1 258 sauver.class
10/06/2002  10:53                   83 out

E:\data\serge\JAVA\poly juin 2002\Chapitre 3\sauveAttributs>more out
personne(Jean,Dupont,27)
personne(Pauline,Garcia,24)
personne(Gilles,Dumond,56)

4.10. Binärdateien

4.10.1. Die Klasse RandomAccessFile

Die Klasse RandomAccessFile ermöglicht es Ihnen, Binärdateien zu verwalten, insbesondere solche mit einer festen Struktur, wie sie in C/C++ vorkommen. Hier sind einige nützliche Methoden und Konstruktoren:

RandomAccessFile(String filename, String mode)
Konstruktor – öffnet die angegebene Datei im angegebenen Modus. Der Modus kann einer der folgenden sein:
r: zum Lesen öffnen
rw: zum Lesen und Schreiben öffnen
void writeTTT(TTT value)
schreibt den Wert in die Datei. TTT steht für den Werttyp. Die Speicherdarstellung des Werts wird unverändert in die Datei geschrieben. Daher gibt es writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat usw. Um eine Zeichenkette zu schreiben, verwende writeBytes(String string).
TTT readTTT()
Liest einen Wert vom Typ TTT und gibt ihn zurück. Beispiele sind readBoolean, readByte, readInt, readDouble, readLong, readFloat usw. Die Methode read() liest ein Byte.
long length()
Dateigröße in Bytes
long getFilePointer()
Aktuelle Position des Dateizeigers
void seek(long pos)
setzt den Dateizeiger auf Byte pos

4.10.2. Die Klasse „Article“

In allen folgenden Beispielen wird die folgende Artikelklasse verwendet:

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

Die obige Java-Klasse „Item“ entspricht der folgenden C-Struktur

struct article{
    char code[4];
    char nom[20];
    double prix;
    int stockActuel;
    int stockMinimum;
}//structure

Auf diese Weise beschränken wir den Code auf 4 Zeichen und den Namen auf 20.

4.10.3. Einen Datensatz erstellen

Das folgende Programm schreibt einen Datensatz in eine Datei namens „data“:

// imported classes
import java.io.*;

public class test1{

// tests the writing of a structure (in the C sense) to a binary file

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

    public static void main(String arg[]){

         // we define the binary file in which the items will be stored
        RandomAccessFile fic=null;

         // we define an article
        article art=new article();
        art.code="a100";
        art.nom="velo";
        art.prix=1000.80;
        art.stockActuel=100;
        art.stockMinimum=10;

         // we define the file
        try{
                fic=new RandomAccessFile("data","rw");
        } catch (Exception E){
                erreur("Impossible d'ouvrir le fichier data",1);
        }//try-catch

        // we write
        try{
            ecrire(fic,art);
        } catch (IOException E){
                erreur("Erreur lors de l'écriture de l'enregistrement",2);
        }//try-catch

        // it's over
        try{
            fic.close();
        } catch (Exception E){
            erreur("Impossible de fermer le fichier data",2);
        }//try-catch
  }//hand

   // writing method
  public static void ecrire(RandomAccessFile fic, article art) throws IOException{
        // code
      fic.writeBytes(art.code);
       // name limited to 20 characters
      art.nom=art.nom.trim();
      int l=art.nom.length();
      int nbBlancs=20-l;
      if(nbBlancs>0){
          String blancs="";
          for(int i=0;i<nbBlancs;i++) blancs+=" ";
          art.nom+=blancs;
      } else art.nom=art.nom.substring(0,20);
      fic.writeBytes(art.nom);
       // the price
      fic.writeDouble(art.prix);
       // inventories
      fic.writeInt(art.stockActuel);
      fic.writeInt(art.stockMinimum);
  }// end write

   // ------------------------erreur
  public static void erreur(String msg, int exitCode){
          System.err.println(msg);
          System.exit(exitCode);
  }// end error
}// fin class

Mit dem folgenden Programm können wir überprüfen, ob die Ausführung erfolgreich war.

4.10.4. Lies einen Datensatz

// imported classes
import java.io.*;

public class test2{

// tests the writing of a structure (in the C sense) to a binary file

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

    public static void main(String arg[]){

         // we define the binary file in which the items will be stored
        RandomAccessFile fic=null;

       // open the file in read mode
      try{
          fic=new RandomAccessFile("data","r");
      } catch (Exception E){
          erreur("Impossible d'ouvrir le fichier data",1);
      }//try-catch

       // we read the single article in the file
    article art=new article();
      try{
          lire(fic,art);
      } catch (IOException E){
          erreur("Erreur lors de la lecture de l'enregistrement",2);
      }//try-catch

       // the record played back is displayed
      affiche(art);

       // it's over
      try{
          fic.close();
      } catch (Exception E){
          erreur("Impossible de fermer le fichier data",2);
      }//try-catch
  }// fine hand

    // reading method
    public static void lire(RandomAccessFile fic, article art) throws IOException{
       // code reading
        art.code="";
        for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
    // name
        art.nom="";
        for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
        art.nom=art.nom.trim();
    // price
        art.prix=fic.readDouble();
    // stocks
        art.stockActuel=fic.readInt();
        art.stockMinimum=fic.readInt();
    }// end write

     // ---------------------affiche
    public static void affiche(article art){
        System.out.println("code : "+art.code);
        System.out.println("nom : "+art.nom);
        System.out.println("prix : "+art.prix);
        System.out.println("Stock actuel : "+art.stockActuel);
        System.out.println("Stock minimum : "+art.stockMinimum);
    }// end poster

     // ------------------------erreur
    public static void erreur(String msg, int exitCode){
                System.err.println(msg);
                System.exit(exitCode);
    }// end error
}// end class

Die Ausführungsergebnisse lauten wie folgt:

E:\data\serge\JAVA\random>java test2
code : a100
nom : velo
prix : 1000.8
Stock actuel : 100
Stock minimum : 10    

Wir rufen erfolgreich den Datensatz ab, der vom Schreibprogramm geschrieben wurde.

4.10.5. Konvertierung von Text in Binärdaten

Das folgende Programm ist eine Erweiterung des Programms zum Schreiben von Datensätzen. Wir schreiben nun mehrere Datensätze in eine Binärdatei namens data.bin. Die Daten stammen aus der folgenden Datei data.txt:

E:\data\serge\JAVA\random>more data.txt
a100:velo:1000:100:10
b100:pompe:65:6:2
c100:arc:867:10:5
d100:fleches - lot de 6:450:12:8
e100:jouet:10:2:3
// imported classes
import java.io.*;
import java.util.*;

public class test3{

// text file --> binary file

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

    public static void main(String arg[]){

         // we define the binary file in which the items will be stored
        RandomAccessFile dataBin=null;
        try{
                dataBin=new RandomAccessFile("data.bin","rw");
        } catch (Exception E){
                erreur("Impossible d'ouvrir le fichier data.bin",1);
        }

         // data are taken from a text file
    BufferedReader dataTxt=null;
        try{
            dataTxt=new BufferedReader(new FileReader("data.txt"));
        } catch (IOException E){
            erreur("Impossible d'ouvrir le fichier data.txt",2);
        }

       // .txt file --> .bin file
      String ligne=null;
      String[] champs=null;
      int numLigne=0;
      String champ=null;
    article art=new article();    // item to be created
      try{
          while((ligne=dataTxt.readLine())!=null){
          // a + line
              numLigne++;
         // decomposition into fields
        champs=ligne.split(":");
         // 5 fields are required
              if(champs.length!=5)
                  erreur("Ligne "+numLigne+" erronée dans data.txt",3);
         //code
              art.code=champs[0];
              if(art.code.length()!=4) 
            erreur("Code erroné en ligne "+numLigne+" du fichier data.txt",12);
         // last name, first name
              art.nom=champs[1];
         // price
              try{
                  art.prix=Double.parseDouble(champs[2]);
              } catch (Exception E){
                  erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
              }
        // current stock
              try{
                  art.stockActuel=Integer.parseInt(champs[3]);
              } catch (Exception E){
                  erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
              }
        // current stock
              try{
                  art.stockActuel=Integer.parseInt(champs[3]);
              } catch (Exception E){
                  erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
              }             
               // we write the recording
              try{
                  ecrire(dataBin,art);
              } catch (IOException E){
                  erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
              }
               // move on to the next line
          }// end while
      } catch (IOException E){
          erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
      }        
        // it's over
      try{
                  dataBin.close();
      } catch (Exception E){
                  erreur("Impossible de fermer le fichier data.bin",10);
      }
      try{
                  dataTxt.close();
      } catch (Exception E){
                  erreur("Impossible de fermer le fichier data.txt",11);
      }
  }// fine hand

   // writing method
  public static void ecrire(RandomAccessFile fic, article art) throws IOException{
        // code
      fic.writeBytes(art.code);
       // name limited to 20 characters
      art.nom=art.nom.trim();
      int l=art.nom.length();
      int nbBlancs=20-l;
      if(nbBlancs>0){
          String blancs="";
          for(int i=0;i<nbBlancs;i++) blancs+=" ";
          art.nom+=blancs;
      } else art.nom=art.nom.substring(0,20);
      fic.writeBytes(art.nom);
       // the price
      fic.writeDouble(art.prix);
       // inventories
      fic.writeInt(art.stockActuel);
      fic.writeInt(art.stockMinimum);
  }// end write

     // ------------------------erreur
    public static void erreur(String msg, int exitCode){
                System.err.println(msg);
                System.exit(exitCode);
    }// end error

}// end class

Mit dem folgenden Programm können Sie überprüfen, ob dieses Programm korrekt funktioniert hat.

4.10.6. Konvertierung von Binärdaten in Text

Das folgende Programm liest den Inhalt der zuvor erstellten Binärdatei data.bin und schreibt diesen in die Textdatei data.text. Wenn alles gut geht, sollte die Datei data.text mit der Originaldatei data.txt identisch sein.

// imported classes
import java.io.*;
import java.util.*;

public class test5{

// text file --> binary file

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

     // hand
    public static void main(String arg[]){

         // we define the binary file in which the items will be stored
        RandomAccessFile dataBin=null;
        try{
                dataBin=new RandomAccessFile("data.bin","r");
        } catch (Exception E){
                erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
        }

         // data is written to a text file
    PrintWriter dataTxt=null;
        try{
            dataTxt=new PrintWriter(new FileWriter("data.text"));
        } catch (IOException E){
            erreur("Impossible d'ouvrir le fichier data.text en écriture",2);
        }

      // .bin file --> .text file
    article art=new article();    // item to be created

       // we process the binary file
      int numRecord=0;
      long l=0;    // file size
      try{
          l=dataBin.length();
      } catch (IOException e){
          erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
      }
      long pos=0;    // current position in file
      try{
          pos=dataBin.getFilePointer();
      } catch (IOException e){
          erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
      }

     // as long as you haven't passed the end of the file
        while(pos<l){
            // read and use current recordings
            numRecord++;
            try{
                lire(dataBin,art);
            } catch (Exception e){
                erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
            }
            affiche(art);

             // write the corresponding text line in dataTxt
         dataTxt.println(art.code.trim()+":"+art.nom.trim()+":"+art.prix+":"+art.stockActuel+":"+art.stockMinimum);

             // shall we continue?
            try{
                pos=dataBin.getFilePointer();
            } catch (IOException e){
                erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
            }
        }// end while

       // it's over
      try{
                  dataBin.close();
      } catch (Exception E){
                  erreur("Impossible de fermer le fichier data.bin",2);
      }

      try{
          dataTxt.close();
      } catch (Exception E){
                  erreur("Impossible de fermer le fichier data.text",2);
      }

  }// fine hand

     // reading method
    public static void lire(RandomAccessFile fic, article art) throws IOException{
      // code reading
        art.code="";
        for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
    // name
        art.nom="";
        for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
        art.nom=art.nom.trim();
    // price
        art.prix=fic.readDouble();
    // stocks
        art.stockActuel=fic.readInt();
        art.stockMinimum=fic.readInt();
    }// end write

     // ---------------------affiche
    public static void affiche(article art){
        System.out.println("code : "+art.code);
        System.out.println("nom : "+art.nom);
        System.out.println("prix : "+art.prix);
        System.out.println("Stock actuel : "+art.stockActuel);
        System.out.println("Stock minimum : "+art.stockMinimum);
    }// end poster

     // ------------------------erreur
    public static void erreur(String msg, int exitCode){
                System.err.println(msg);
                System.exit(exitCode);
    }// end error
}// fin class

Hier ist ein Beispiel für die Ausführung:

E:\data\serge\JAVA\random>java test5
code : a100
nom : velo
prix : 1000.0
Stock actuel : 100
Stock minimum : 0
code : b100
nom : pompe
prix : 65.0
Stock actuel : 6
Stock minimum : 0
code : c100
nom : arc
prix : 867.0
Stock actuel : 10
Stock minimum : 0
code : d100
nom : fleches - lot de 6
prix : 450.0
Stock actuel : 12
Stock minimum : 0
code : e100
nom : jouet
prix : 10.0
Stock actuel : 2
Stock minimum : 0

E:\data\serge\JAVA\random>more data.text
a100:velo:1000.0:100:0
b100:pompe:65.0:6:0
c100:arc:867.0:10:0
d100:fleches - lot de 6:450.0:12:0
e100:jouet:10.0:2:0

4.10.7. Direkter Zugriff auf Datensätze

Dieses letzte Programm demonstriert die Möglichkeit, direkt auf Datensätze in einer Binärdatei zuzugreifen. Es zeigt den Datensatz aus der Datei data.bin an, dessen Nummer als Parameter übergeben wird, wobei der erste Datensatz die Nummer 1 hat.

// imported classes
import java.io.*;
import java.util.*;

public class test6{

// text file --> binary file

     // article structure
    private static class article{
         // we define the structure
        public String code;
        public String nom;
        public double prix;
        public int stockActuel;
        public int stockMinimum;
  }//item class

     // hand
    public static void main(String[] args){

       // check the arguments
      int nbArguments=args.length;
      String syntaxe="syntaxe : pg numéro_de_fiche";
      if(nbArguments!=1)
          erreur(syntaxe,20);
     // check plug no
      int numRecord=0;
      try{
          numRecord=Integer.parseInt(args[0]);
      } catch(Exception e){
          erreur(syntaxe+"\nNuméro de fiche incorrect",21);
      }

       // open the binary file for reading
    RandomAccessFile dataBin=null;
      try{
          dataBin=new RandomAccessFile("data.bin","r");
      } catch (Exception E){
          erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
      }

       // position yourself on the desired card
      try{
          dataBin.seek((numRecord-1)*40);
      } catch (Exception e){
          erreur("La fiche "+numRecord+" n'existe pas",23);
      }

       // we read it
    article art=new article();
      try{
          lire(dataBin,art);
      } catch (Exception e){
          erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
      }

       // we display it
      affiche(art);

       // it's over
      try{
          dataBin.close();
      } catch (Exception E){
          erreur("Impossible de fermer le fichier data.bin",2);
      }//try-catch

  }// fine hand

    // reading method
    public static void lire(RandomAccessFile fic, article art) throws IOException{
       // code reading
        art.code="";
        for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
    // name
        art.nom="";
        for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
        art.nom=art.nom.trim();
    // price
        art.prix=fic.readDouble();
    // stocks
        art.stockActuel=fic.readInt();
        art.stockMinimum=fic.readInt();
    }// end write

     // ---------------------affiche
    public static void affiche(article art){
        System.out.println("code : "+art.code);
        System.out.println("nom : "+art.nom);
        System.out.println("prix : "+art.prix);
        System.out.println("Stock actuel : "+art.stockActuel);
        System.out.println("Stock minimum : "+art.stockMinimum);
    }// end poster

     // ------------------------erreur
    public static void erreur(String msg, int exitCode){
                System.err.println(msg);
                System.exit(exitCode);
    }// end error
}// fin class

Hier sind einige Beispiele für die Ausführung:

E:\data\serge\JAVA\random>java test6 2
code : b100
nom : pompe
prix : 65.0
Stock actuel : 6
Stock minimum : 0

E:\data\serge\JAVA\random>java.bat test6 20
Erreur lors de la lecture de l'enregistrement 20

4.11. Verwendung regulärer Ausdrücke

4.11.1. Das Paket java.util.regex in Java

Das Paket java.util.regex ermöglicht die Verwendung regulärer Ausdrücke. Mit diesen können Sie das Format einer Zeichenfolge überprüfen. Sie können beispielsweise sicherstellen, dass eine Zeichenfolge, die ein Datum darstellt, im Format tt/mm/jj vorliegt. Dazu verwenden Sie ein Muster und vergleichen die Zeichenfolge mit diesem Muster. In diesem Beispiel müssen d, m und y Ziffern sein. Das Muster für ein gültiges Datumsformat lautet daher „\d\d/\d\d/\d\d“, wobei das Symbol \d für eine Ziffer steht. Die folgenden Symbole können in einem Muster verwendet werden (Microsoft-Dokumentation):

Zeichen
Beschreibung
\
Bezeichnet das folgende Zeichen als Sonderzeichen oder Literal. Beispielsweise entspricht „n“ dem Zeichen „n“. „\n“ entspricht einem Zeilenumbruchzeichen. Die Zeichenfolge „\\“ entspricht „\“, während „\(" dem Zeichen „(“ entspricht.
^
Stimmt mit dem Anfang der Eingabe überein.
$
Stimmt mit dem Ende der Eingabe überein.
*
Stimmt nullmal oder öfter mit dem vorangehenden Zeichen überein. Somit passt „zo*“ zu „z“ oder „zoo“.
+
Stimmt mit dem vorangehenden Zeichen ein- oder mehrmals überein. So passt „zo+“ zu „zoo“, aber nicht zu „z“.
?
Passt null- oder einmal auf das vorangehende Zeichen. Zum Beispiel passt „a?ve?“ auf „ve“ in „lever“.
.
Stimmt mit einem beliebigen einzelnen Zeichen überein, mit Ausnahme des Zeilenumbruchzeichens.
(Muster)
Sucht nach dem Muster und speichert die Übereinstimmung. Die übereinstimmende Teilzeichenfolge kann aus der resultierenden Matches-Sammlung mit Item [0]...[n] abgerufen werden. Um Übereinstimmungen mit Zeichen innerhalb von Klammern ( ) zu finden, verwende „\(" oder „\)“.
x|y
Passt entweder auf x oder y. Beispielsweise passt „z|foot“ auf „z“ oder „foot“. „(z|f)oo“ passt auf „zoo“ oder „foo“.
{n}
n ist eine nicht-negative ganze Zahl. Passt genau auf n Vorkommen des Zeichens. Beispielsweise passt „o{2}“ nicht auf „o“ in „Bob“, sondern auf die ersten beiden „o“s in „fooooot“.
{n,}
n ist eine nicht-negative ganze Zahl. Passt auf mindestens n Vorkommen des Zeichens. Beispielsweise passt „o{2,}“ nicht auf „o“ in „Bob“, sondern auf alle „o“s in „fooooot“. „o{1,}“ entspricht „o+“ und „o{0,}“ entspricht „o*“.
{n,m}
m und n sind nicht-negative ganze Zahlen. Es werden mindestens n und höchstens m Vorkommen des Zeichens gefunden. Beispielsweise passt „o{1,3}“ auf die ersten drei „o“s in „foooooot“, und „o{0,1}“ entspricht „o?“.
[xyz]
Zeichensatz. Findet eines der angegebenen Zeichen. Beispielsweise passt „[abc]“ auf das „a“ in „plat“.
[^xyz]
Negativer Zeichensatz. Findet jedes Zeichen, das nicht aufgeführt ist. Beispielsweise findet „[^abc]“ das „p“ in „plat“.
[a-z]
Zeichenbereich. Entspricht jedem Zeichen im angegebenen Bereich. Beispielsweise entspricht „[a-z]“ jedem Kleinbuchstaben zwischen „a“ und „z“.
[^m-z]
Negativer Zeichenbereich. Passt auf jedes Zeichen, das nicht im angegebenen Bereich liegt. Beispielsweise passt „[^m-z]“ auf jedes Zeichen, das nicht zwischen „m“ und „z“ liegt.
\b
Passt auf eine Wortgrenze, d. h. die Position zwischen einem Wort und einem Leerzeichen. Beispielsweise passt „er\b“ auf „er“ in „lever“, aber nicht auf „er“ in „verb“.
\B
Passt auf eine Grenze, die kein Wort darstellt. „en*t\B“ passt auf „ent“ in „bien entendu“.
\d
Passt auf ein Zeichen, das eine Ziffer darstellt. Entspricht [0-9].
\D
Passt auf ein Zeichen, das keine Ziffer ist. Entspricht [^0-9].
\f
Entspricht einem Zeilenumbruchzeichen.
\n
Entspricht einem Zeilenumbruchzeichen.
\r
Entspricht einem Wagenrücklaufzeichen.
\s
Entspricht einem beliebigen Leerzeichen, einschließlich Leerzeichen, Tabulator, Seitenumbruch usw. Entspricht „[ \f\n\r\t\v]“.
\S
Entspricht jedem Zeichen, das kein Leerzeichen ist. Entspricht "[^ \f\n\r\t\v]".
\t
Entspricht einem Tabulatorzeichen.
\v
Entspricht einem vertikalen Tabulatorzeichen.
\w
Entspricht jedem Zeichen, das ein Wort darstellt, einschließlich Unterstrich. Entspricht „[A-Za-z0-9_]“.
\W
Entspricht jedem Zeichen, das kein Wort darstellt. Entspricht „[^A-Za-z0-9_]“.
\num
Passt auf num, wobei num eine positive ganze Zahl ist. Bezieht sich auf gespeicherte Übereinstimmungen. Beispielsweise passt „(.)\1“ auf zwei aufeinanderfolgende identische Zeichen.
\n
Entspricht n, wobei n ein oktaler Escape-Wert ist. Oktale Escape-Werte müssen aus 1, 2 oder 3 Ziffern bestehen. Beispielsweise stimmen sowohl „\11“ als auch „\011“ mit einem Tabulatorzeichen überein. „\0011“ entspricht „\001“ & „1“. Oktale Escape-Werte dürfen 256 nicht überschreiten. Ist dies der Fall, werden im Ausdruck nur die ersten beiden Ziffern berücksichtigt. Ermöglicht die Verwendung von ASCII-Codes in regulären Ausdrücken.
\xn
Entspricht n, wobei n ein hexadezimaler Escape-Wert ist. Hexadezimale Escape-Werte müssen aus genau zwei Ziffern bestehen. Beispielsweise entspricht „\x41“ dem Zeichen „A“. „\x041“ entspricht „\x04“ und „1“. Ermöglicht die Verwendung von ASCII-Codes in regulären Ausdrücken.

Ein Element in einem Muster kann einmal oder mehrmals vorkommen. Sehen wir uns einige Beispiele mit dem Symbol \d an, das eine einzelne Ziffer darstellt:

Muster
Bedeutung
\d
eine Ziffer
\d?
0 oder 1 Ziffer
\d*
0 oder mehr Ziffern
\d+
1 oder mehr Ziffern
\d{2}
2 Ziffern
\d{3,}
mindestens 3 Ziffern
\d{5,7}
zwischen 5 und 7 Ziffern

Stellen wir uns nun ein Modell vor, das das erwartete Format einer Zeichenkette beschreiben kann:

Zielzeichenfolge
Muster
ein Datum im Format TT/MM/JJ
\d{2}/\d{2}/\d{2}
eine Uhrzeit im Format hh:mm:ss
\d{2}:\d{2}:\d{2}
eine vorzeichenlose Ganzzahl
\d+
eine Folge von Leerzeichen, die leer sein kann
\s*
eine vorzeichenlose Ganzzahl, der Leerzeichen vorangehen oder folgen können
\s*\d+\s*
eine ganze Zahl, die vorzeichenbehaftet sein kann und der Leerzeichen vorangehen oder folgen können
\s*[+|-]?\s*\d+\s*
eine vorzeichenlose reelle Zahl, der Leerzeichen vorangestellt oder nachgestellt sein können
\s*\d+(.\d*)?\s*
eine reelle Zahl, die vorzeichenbehaftet sein kann und der Leerzeichen vorangehen oder nachfolgen können
\s*[+|]?\s*\d+(.\d*)?\s*
eine Zeichenkette, die das Wort „just“ enthält
\bjuste\b
  

Sie können angeben, wo in der Zeichenfolge nach dem Muster gesucht werden soll:

Muster
Bedeutung
^Muster
Das Muster steht am Anfang der Zeichenfolge
Muster$
Das Muster beendet die Zeichenkette
^Muster$
Das Muster beginnt und endet die Zeichenfolge
Muster
Das Muster wird ab dem Anfang an einer beliebigen Stelle in der Zeichenfolge gesucht.
Suchzeichenfolge
Muster
eine Zeichenfolge, die mit einem Ausrufezeichen endet
!$
eine Zeichenfolge, die mit einem Punkt endet
\.$
eine Zeichenkette, die mit der Sequenz // beginnt
^//
eine Zeichenfolge, die aus einem einzelnen Wort besteht, optional gefolgt von oder vorangestellt durch Leerzeichen
^\s*\w+\s*$
eine Zeichenfolge, die aus zwei Wörtern besteht, optional gefolgt von oder vorangestellt durch Leerzeichen
^\s*\w+\s*\w+\s*$
eine Zeichenfolge, die das Wort „secret“ enthält
\bsecret\b

Teilmuster eines Musters können „extrahiert“ werden. So können wir nicht nur überprüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht, sondern auch die Elemente aus dieser Zeichenfolge extrahieren, die den in Klammern eingeschlossenen Teilmustern des Musters entsprechen. Wenn wir beispielsweise eine Zeichenfolge analysieren, die ein Datum im Format dd/mm/yy enthält, und wir außerdem die Elemente dd, mm und yy aus diesem Datum extrahieren möchten, würden wir das Muster (\d\d)/(\d\d)/(\d\d) verwenden.

4.11.2. Prüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht

Mit der Pattern-Klasse können Sie prüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht. Verwenden Sie dazu die statische Methode

boolean Matches(String modèle, String chaine)

mit folgenden Parametern: pattern: das zu prüfende Muster, string: die Zeichenkette, die mit dem Muster verglichen werden soll. Das Ergebnis ist der boolesche Wert true, wenn string mit pattern übereinstimmt, andernfalls false.

Hier ein Beispiel:

import java.io.*;
import java.util.regex.*;

// regular expression management
public class regex1 {
  public static void main(String[] args){
    // a regular expression template
    String modèle1="^\\s*\\d+\\s*$";
    // compare a copy with the model
    String exemplaire1="  123  ";
    if (Pattern.matches(modèle1,exemplaire1)){
      affiche("["+exemplaire1 + "] correspond au modèle ["+modèle1+"]");
    }else{
      affiche("["+exemplaire1 + "] ne correspond pas au modèle ["+modèle1+"]");
    }//if
    String exemplaire2="  123a  ";
    if (Pattern.matches(modèle1,exemplaire2)){
      affiche("["+exemplaire2 + "] correspond au modèle ["+modèle1+"]");
    }else{
      affiche("["+exemplaire2 + "] ne correspond pas au modèle ["+modèle1+"]");
    }//if
  }//hand

  public static void affiche(String msg){
    System.out.println(msg);
  }//poster
}//class

und die Ausführungsergebnisse:

[  123  ] correspond au modèle [^\s*\d+\s*$]
[  123a  ] ne correspond pas au modèle [^\s*\d+\s*$]

Beachten Sie, dass im Muster „^\s*\d+\s*$“ das Zeichen \ aufgrund der spezifischen Interpretation dieses Zeichens durch Java doppelt geschrieben werden muss. Wir schreiben daher: String pattern1="^\\s*\\d+\\s*$";

4.11.3. Alle Elemente einer Zeichenkette finden, die einem Muster entsprechen

Betrachten Sie das Muster „\d+“ und die Zeichenkette „ 123 456 789 “. Das Muster kommt an drei verschiedenen Stellen in der Zeichenkette vor. Mit den Klassen Pattern und Matcher können Sie die verschiedenen Vorkommen eines Musters in einer Zeichenkette abrufen. Die Klasse Pattern ist die Klasse, die reguläre Ausdrücke verarbeitet. Ein regulärer Ausdruck, der mehr als einmal verwendet wird, muss „kompiliert“ werden. Dies beschleunigt die Mustersuche in Zeichenfolgen. Die statische Methode compile übernimmt diese Aufgabe:

public static Pattern compile(String regex)

Sie nimmt die Musterzeichenfolge als Parameter entgegen und gibt ein Pattern-Objekt zurück. Um das Muster eines Pattern-Objekts mit einer Zeichenfolge zu vergleichen, verwenden wir die Matcher-Klasse. Diese Klasse ermöglicht den Vergleich eines Musters mit einer Zeichenfolge. Aus einem Pattern-Objekt lässt sich mithilfe der matcher-Methode ein Matcher-Objekt ableiten:

public Matcher matcher(CharSequence input)

input ist die Zeichenkette, die mit dem Muster verglichen werden soll.

Um also das Muster „\d+“ mit der Zeichenkette „ 123 456 789 “ zu vergleichen, können Sie wie folgt ein Matcher-Objekt erstellen:

Pattern regex=Pattern.compile("\\d+");
Matcher résultats=regex.matcher("  123  456  789  ");

Mit dem oben genannten Ergebnisse-Objekt können wir die verschiedenen Vorkommen des Musters in der Zeichenkette abrufen. Dazu verwenden wir die folgenden Methoden der Matcher-Klasse:

public boolean find()
public String group()
public int start()
public Matcher reset()

Die Methode find durchsucht die untersuchte Zeichenkette nach dem ersten Vorkommen des Musters. Ein zweiter Aufruf von find sucht nach dem nächsten Vorkommen und so weiter. Die Methode gibt true zurück, wenn sie das Muster findet, andernfalls false. Der Teil der Zeichenkette, der dem letzten von „find“ gefundenen Vorkommen entspricht, wird mit der Methode „group“ abgerufen, seine Position mit der Methode „start“. Wenn wir also, um das vorherige Beispiel fortzusetzen, alle Vorkommen des Musters „\d+“ in der Zeichenkette „ 123 456 789 “ anzeigen möchten, würden wir schreiben:

while(résultats.find()){
    System.out.println("séquence " + résultats.group() + " trouvée en position " + résultats.start());
    }//while

Mit der Methode „reset“ können Sie das Matcher-Objekt auf den Anfang der Zeichenkette zurücksetzen, die mit dem Muster verglichen wird. Auf diese Weise findet die Methode „find“ dann wieder das erste Vorkommen des Musters.

Hier ist ein vollständiges Beispiel:

import java.io.*;
import java.util.regex.*;

// regular expression management
public class regex2 {
  public static void main(String[] args){
    // several occurrences of the model in the copy
    String modèle2="\\d+";
    Pattern regex2=Pattern.compile(modèle2);
    String exemplaire3="  123  456 789";
    // search for model occurrences in the copy
    Matcher matcher2=regex2.matcher(exemplaire3);
    while(matcher2.find()){
      affiche("séquence " + matcher2.group() + " trouvée en position " + matcher2.start());
    }//while
  }//Main

  public static void affiche(String msg){
    System.out.println(msg);
  }//poster
}//class

Ausführungsergebnisse:

Modèle=[\d+],exemplaire=[  123  456  789 ]
Il y a 3 occurrences du modèle dans l'exemplaire
123 en position 2
456 en position 7
789 en position 12

4.11.4. Teile eines Musters extrahieren

Teilmengen eines Musters können „extrahiert“ werden. So können wir nicht nur überprüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht, sondern auch die Elemente aus dieser Zeichenfolge extrahieren, die den in Klammern eingeschlossenen Teilmengen des Musters entsprechen. Wenn wir beispielsweise eine Zeichenfolge analysieren, die ein Datum im Format dd/mm/yy enthält, und wir außerdem die Elemente dd, mm und yy aus diesem Datum extrahieren möchten, würden wir das Muster (\d\d)/(\d\d)/(\d\d) verwenden.

Betrachten wir das folgende Beispiel:

import java.io.*;
import java.util.regex.*;

// regular expression management
public class regex3 {
  public static void main(String[] args){
    // capture elements in the model
    String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
    Pattern regex3=Pattern.compile(modèle3);
    String exemplaire4="Il est 18:05:49";
    // model checking
    Matcher résultat=regex3.matcher(exemplaire4);
    if (résultat.find()){
      // the copy corresponds to the model
      affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
      // display groups
      for (int i=0;i<=résultat.groupCount();i++){
        affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
      }//for
      }else{
        // the copy does not correspond to the model
        affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
      }
    }//Main

    public static void affiche(String msg){
      System.out.println(msg);
    }//poster
}//class

Die Ausführung dieses Programms liefert folgende Ergebnisse:

L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13

Die neue Funktion ist im folgenden Codeausschnitt zu finden:

    // model checking
    Matcher résultat=regex3.matcher(exemplaire4);
    if (résultat.find()){
      // the copy corresponds to the model
      affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
      // display groups
      for (int i=0;i<=résultat.groupCount();i++){
        affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
      }//for
      }else{
        // the copy does not correspond to the model
        affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
      }

Die Zeichenkette example4 wird mithilfe der find-Methode mit dem Muster regex3 verglichen. In der Zeichenkette example4 wird dann eine Übereinstimmung mit dem Muster regex3 gefunden. Wenn das Muster in Klammern eingeschlossene Teilmengen enthält, sind diese über verschiedene Methoden der Matcher-Klasse zugänglich:


public int groupCount()
public String group(int group)
public int start(int group)

Die Methode groupCount gibt die Anzahl der im Muster gefundenen Untergruppen zurück, und group(i) gibt die Untergruppe Nummer i zurück. Diese befindet sich in der Zeichenkette an der durch start(i) angegebenen Position. Im Beispiel bedeutet dies:

L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13

Der erste Aufruf der find-Methode findet die Zeichenfolge 18:05:49 und erstellt automatisch die drei Teilmengen, die durch die Klammern im Muster definiert sind, nämlich 18, 05 und 49.

4.11.5. Ein Lernprogramm

Es kann manchmal eine echte Herausforderung sein, den regulären Ausdruck zu finden, mit dem wir überprüfen können, ob eine Zeichenkette einem bestimmten Muster entspricht. Mit dem folgenden Programm können Sie üben. Es fragt nach einem Muster und einer Zeichenkette und gibt dann an, ob die Zeichenkette dem Muster entspricht oder nicht.

import java.io.*;
import java.util.regex.*;

// regular expression management
public class regex4 {
  public static void main(String[] args){

    // data
    String modèle=null,chaine=null;
    Pattern regex=null;
    BufferedReader IN=null;
    Matcher résultats=null;
    int nbOccurrences=0;

    // error management
    try{
      // the user is asked for models and samples to compare with this one
      while(true){
        // iNPUTS
        IN=new BufferedReader(new InputStreamReader(System.in));
        // the model is requested
        System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
        modèle=IN.readLine();
        // finished?
        if(modèle.trim().toLowerCase().equals("fin")) break;
        // we create the regular expression
        regex=Pattern.compile(modèle);
        // the user is asked for the specimens to be compared with the model
        while(true){
          System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
          chaine=IN.readLine();
          // finished?
          if(chaine.trim().toLowerCase().equals("fin")) break;
          // create the matcher object
          résultats=regex.matcher(chaine);
          // search for occurrences of the
          nbOccurrences=0;
          while(résultats.find()){
            // we have an occurrence
            nbOccurrences++;
            // we display it
            System.out.println("J'ai trouvé la correspondance ["+résultats.group()
            +"] en position "+résultats.start());
            // display of sub-elements
            if(résultats.groupCount()!=1){
              for(int j=1;j<=résultats.groupCount();j++){
                System.out.println("\tsous-élément ["+résultats.group(j)+"] en position "+
                  résultats.start(j));
              }//for j
            }//if
            // next channel
          }//while(résultats.find())
          // was at least one occurrence found?
          if(nbOccurrences==0){
            System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
          }//if
          // next model
        }//while(true)
      }//while(true)
    }catch(Exception ex){
      // error
      System.err.println("Erreur : "+ex.getMessage());
      // end with error
      System.exit(1);
    }//try-catch
    // end
    System.exit(0);
  }//Main
}//class

Hier ist ein Ausführungsbeispiel:

Tapez le modèle à tester ou fin pour arrêter :\d+
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :123 456 789
J'ai trouvé la correspondance [123] en position 0
J'ai trouvé la correspondance [456] en position 4
J'ai trouvé la correspondance [789] en position 8
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :(\d\d):(\d\d)
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :14:15
abcd 17:18 xyzt
J'ai trouvé la correspondance [14:15] en position 0
        sous-élément [14] en position 0
        sous-élément [15] en position 3
J'ai trouvé la correspondance [17:18] en position 11
        sous-élément [17] en position 11
        sous-élément [18] en position 14
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :^\s*\d+\s*$
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :  1456
J'ai trouvé la correspondance [  1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :^\s*(\d+)\s*$
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :1456
J'ai trouvé la correspondance [1456] en position 0
        sous-élément [1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :abcd 1
456
Je n'ai pas trouvé de correspondances
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :fin

4.11.6. Die split-Methode der Pattern-Klasse

Betrachten wir eine Zeichenkette, die aus Feldern besteht, die durch eine Trennzeichenfolge getrennt sind, die mit einem regulären Ausdruck ausgedrückt wird. Wenn die Felder beispielsweise durch das Zeichen getrennt sind, dem eine beliebige Anzahl von Leerzeichen vorangeht oder folgt, lautet der reguläre Ausdruck, der die Feldtrennzeichenfolge modelliert, „\s*,\s*“. Die split-Methode der Pattern-Klasse ermöglicht es uns, die Felder in einem Array abzurufen:


public String[] split(CharSequence input)

Die Eingabezeichenfolge wird in Felder aufgeteilt, die durch ein Trennzeichen getrennt sind, das dem Muster des aktuellen Pattern-Objekts entspricht. Um die Felder aus einer Zeile abzurufen, in der das Feldtrennzeichen ein Komma ist, dem eine beliebige Anzahl von Leerzeichen vorangeht oder folgt, würden wir schreiben:

    // a line
    String ligne="abc  ,, def  , ghi";
    // a model
    Pattern modèle=Pattern.compile("\\s*,\\s*");
    // decomposition of line into fields
    String[] champs=modèle.split(ligne);

Das gleiche Ergebnis lässt sich mit der Methode „split“ der Klasse „String“ erzielen:


public String[] split(String regex)

Hier ist ein Testprogramm:

import java.io.*;
import java.util.regex.*;

// regular expression management
public class split1 {
  public static void main(String[] args){
    // a line
    String ligne="abc  ,, def  , ghi";
    // a model
    Pattern modèle=Pattern.compile("\\s*,\\s*");
    // decomposition of line into fields
    String[] champs=modèle.split(ligne);
    // display
    for(int i=0;i<champs.length;i++){
      System.out.println("champs["+i+"]=["+champs[i]+"]");
    }//for
    // another way of doing things
    champs=ligne.split("\\s*,\\s*");
    // display
    for(int i=0;i<champs.length;i++){
      System.out.println("champs["+i+"]=["+champs[i]+"]");
    }//for
  }//Main
}//class

Ausführungsergebnisse:

champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]
champs[0]=[abc]
champs[1]=[]
champs[2]=[def]
champs[3]=[ghi]

4.12. Übungen

4.12.1. Übung 1

Unter Unix werden Programme oft wie folgt aufgerufen:

$ pg -o1 v1 v2 ... -o2 v3 v4 …

wobei -oi eine Option und vi einen mit dieser Option verbundenen Wert darstellt. Wir möchten eine Optionsklasse erstellen, die die Argumentzeichenfolge -o1 v1 v2 ... -o2 v3 v4 … analysiert, um die folgenden Entitäten zu konstruieren:

ValidOptions
ein Wörterbuch (Hashtable), dessen Schlüssel die gültigen oi-Optionen sind. Der dem Schlüssel „oi“ zugeordnete Wert ist ein Vektor (Vector), dessen Elemente die Werte v1, v2, … sind, die der Option -oi zugeordnet sind
invalidOptions
Wörterbuch (Hashtable), dessen Schlüssel die ungültigen oi-Optionen sind. Der mit dem Schlüssel oi verknüpfte Wert ist ein Vektor (Vector), dessen Elemente die Werte v1, v2 … sind, die der Option -oi zugeordnet sind
optionsWithout
Zeichenkette (String), die die vi-Werte auflistet, die keiner Option zugeordnet sind
Fehler
eine Ganzzahl, die 0 ist, wenn die Argumentliste keine Fehler enthält, andernfalls:
1: Es gibt ungültige Aufrufparameter
2: Es gibt ungültige Optionen
4: Es gibt Werte, die keiner Option zugeordnet sind
Wenn mehrere Arten von Fehlern vorliegen, werden diese Werte addiert.

Ein Optionsobjekt kann auf vier verschiedene Arten erstellt werden:

public options (String arguments, String optionsAcceptable)

argumente
die zu parsenen Befehlszeilenargumente -o1 v1 v2 ... -o2 v3 v4 …
optionsAcceptable
die Liste der zulässigen Optionen

Beispielaufruf: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");

Hier sind beide Argumente Zeichenfolgen. Wir akzeptieren Fälle, in denen diese Zeichenfolgen in Wörter aufgeteilt und in einem Array von Zeichenfolgen abgelegt wurden. Dies erfordert drei zusätzliche Konstruktoren:

public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)

Die Klasse „options“ verfügt über die folgende Schnittstelle (Getter):

public Hashtable getOptionsValides()

gibt eine Referenz auf das Array „optionsValides“ zurück, das beim Erstellen des Optionsobjekts angelegt wurde

public Hashtable getOptionsInvalides()

gibt eine Referenz auf das Array invalidOptions zurück, das beim Erstellen des Optionsobjekts angelegt wurde

public String getOptionsSans()

Gibt eine Referenz auf die Zeichenkette „optionsWithout“ zurück, die beim Erstellen des Optionsobjekts angelegt wurde

public int getErreur()

Gibt den Wert des Attributs „error“ zurück, das bei der Erstellung des Optionsobjekts angelegt wurde

public String toString()

Wenn keine Fehler vorliegen, werden die Werte der Attribute „optionsValides“, „optionsInvalides“ und „optionsSans“ angezeigt; andernfalls wird die Fehlernummer angezeigt.

Hier ist ein Beispielprogramm:


import java.io.*;
//import options;
 
public class test1{
  
  
  public static void main (String[] arg){
    
    // inlet flow opening
    String ligne;
    BufferedReader IN=null;
    try{
      IN=new BufferedReader(new InputStreamReader(System.in));
    } catch (Exception e){
      affiche(e);
      System.exit(1);
    }
    // read constructor arguments options(String, string)
    String options=null;
    String optionsAcceptables=null;
    while(true){
      System.out.print("Options : ");
      try{
        options=IN.readLine();
      } catch (Exception e){
        affiche(e);
        System.exit(2);
      }
      if(options.length()==0) break;
      System.out.print("Options acceptables: ");
      try{
        optionsAcceptables=IN.readLine();
      } catch (Exception e){
        affiche(e);
        System.exit(2);
      }
      System.out.println(new options(options,optionsAcceptables));
    }// end while
  }//fine hand
 
 
public static void affiche(Exception e){
    System.err.println("Erreur : "+e);
  }
 
}//end of class

Einige Ergebnisse:

C:\Serge\java\options>java test1
Options : 1 2 3 -a a1 a2 -b b1 -c c1 c2 c3 -b b2 b3
Options acceptables: -a -b
Erreur 6
Options valides :(-b,b1,b2,b3)  (-a,a1,a2)
Options invalides : (-c,c1,c2,c3)
Sans options : 1 2 3

4.12.2. Übung 2

Wir möchten eine Klasse „stringtovector“ erstellen, mit der wir den Inhalt eines String-Objekts in ein Vector-Objekt übertragen können. Diese Klasse würde von der Vector-Klasse abgeleitet sein:

class stringtovector extends Vector

und hätte den folgenden Konstruktor:


    private void stringtovector(String S, String separateur, int[] tChampsVoulus,
            boolean strict){
 
        // crée un vecteur avec les champs de la chaîne S
        // celle-ci est constituée de champs séparés par separateur
        // si séparateur=null, la chaîne ne forme qu'un seul champ
        // seuls les champs dont les index sont dans le tableau tChampsVoulus 
        // sont désirés. Les index commencent à 1
        // si tChampsvoulus=null ou de taille nulle, on prend tous les champs
        // si strict=vrai, tous les champs désirés doivent être présents

Die Klasse hätte das folgende private Attribut:

        private int erreur;

Dieses Attribut wird vom vorherigen Konstruktor mit den folgenden Werten gesetzt:

0: Die Konstruktion war erfolgreich

4: Einige erforderliche Felder fehlen, obwohl strict=true

Die Klasse verfügt außerdem über zwei Methoden:

    public int getErreur()

die den Wert des privaten Attributs „error“ zurückgibt.

    public String identite(){

die den Wert des Objekts in der Form (Fehler, Element 1, Element 2, …) anzeigt, wobei die Elemente i die Elemente des aus der Zeichenkette konstruierten Vektors sind.

Ein Testprogramm könnte wie folgt aussehen:


import java.io.*;
//import stringtovector;
 
public class essai2{
  public static void main(String arg[]){
    int[] T1={1,3};
    System.out.println(new stringtovector("a : b : c :d:e",":",T1,true).identite());
    int[] T2={1,3,7};
    System.out.println(new stringtovector("a : b : c :d:e",":",T2,true).identite());
    int [] T3={1,4,7};
    System.out.println(new stringtovector("a : b : c :d:e",":",T3,false).identite());
    System.out.println(new stringtovector("a : b : c :d:e","",T1,false).identite());
    System.out.println(new stringtovector("a : b : c :d:e",null,T1,false).identite());
    int[] T4={1};
    System.out.println(new stringtovector("a : b : c :d:e","!",T4,true).identite());
    int[] T5=null;
    System.out.println(new stringtovector("a : b : c :d:e",":",T5,true).identite());
    System.out.println(new stringtovector("a : b : c :d:e",null,T5,true).identite());
    int[] T6=new int[0];
    System.out.println(new stringtovector("a : b : c :d:e","",T6,true).identite());
    int[] T7={1,3,4};
    System.out.println(new stringtovector("a  b  c d e"," ",T6,true).identite());
  }
}

Die Ergebnisse:

(0,a,c)
(4,a,c)
(0,a,d)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a,b,c,d,e)
(0,a : b : c :d:e)
(0,a : b : c :d:e)
(0,a,b,c,d,e)

Einige Tipps:

  1. Um die Zeichenkette S in Felder aufzuteilen, verwende die split-Methode der String-Klasse.
  2. Speichere die Felder von S in einem Wörterbuch D, das nach der Feldnummer indiziert ist
  3. Rufen Sie aus dem Wörterbuch D nur jene Felder ab, deren Schlüssel (Indizes) im Array tChampsVoulus enthalten sind.

4.12.3. Übung 3

Wir möchten der Klasse **stringtovector** den folgenden Konstruktor hinzufügen:


public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
        
        // crée un vecteur avec les champs de la chaîne S
        // celle-ci est constituée de champs séparés par separateur
        // si séparateur=null, la chaîne ne forme qu'un seul champ
        // seuls les champs dont les index sont dans sChampsVoulus sont désirés
        // les index commencent à 1
        // si sChampsvoulus=null ou "", on prend tous les champs
        // si strict=vrai, tous les champs désirés doivent être présents

Die Liste der gewünschten Felder liegt daher in einer Zeichenkette (String) vor und nicht in einem Array von Ganzzahlen (int[]). Dem privaten Fehlerattribut der Klasse kann ein neuer Wert zugewiesen werden:

2: Die Zeichenkette der Indizes der gewünschten Felder ist falsch

Hier ist ein Beispielprogramm:


import java.io.*;
//import stringtovector;
 
public class essai1{
  public static void main(String arg[]){
    String champs=null;
    System.out.println(new stringtovector("a: b :c :d:e ",":","1 3",true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",":","1 3 7",true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",":","1 4 7",false).identite());
    System.out.println(new stringtovector("a: b :c :d:e ","","1 3",false).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",null,"1 3",false).identite());
    System.out.println(new stringtovector("a: b :c :d:e ","!","1",true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",":","",true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",":",champs,true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",null,champs,true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ","","",true).identite());
    System.out.println(new stringtovector("a: b :c :d:e ",":","1 !",true).identite());
    System.out.println(new stringtovector("a b c d       e "," ","1 3",false).identite());
  }
}

Einige Ergebnisse:

(0,a,c)
(4,a,c)
(0,a,d)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(0,a,b,c,d,e)
(0,a,b,c,d,e)
(0,a: b :c :d:e)
(0,a: b :c :d:e)
(2)
(0,a,c)

Einige Tipps:

  1. Sie müssen auf den Fall des vorherigen Konstruktors zurückgreifen, indem Sie die Felder aus der Zeichenkette sChampsVoulus in ein Array von Ganzzahlen übertragen. Dazu teilen Sie sChampsVoulus mithilfe eines StringTokenizer-Objekts in Felder auf, dessen Attribut countTokens die Anzahl der erhaltenen Felder angibt. Anschließend können Sie ein Array von Ganzzahlen mit der richtigen Größe erstellen und es mit den erhaltenen Feldern füllen.
  2. Um festzustellen, ob ein Feld eine Ganzzahl ist, verwende die Methode Integer.parseInt, um das Feld in eine Ganzzahl zu konvertieren, und behandle die Ausnahme, die ausgelöst wird, wenn diese Konvertierung nicht möglich ist.

4.12.4. Übung 4

Wir möchten eine Klasse „filetovector“ erstellen, mit der wir den Inhalt einer Textdatei in ein Vector-Objekt übertragen können. Diese Klasse würde von der Vector-Klasse abgeleitet sein:

class filetovector extends Vector

und hätte den folgenden Konstruktor:


    // --------------------- constructeur 
    public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
        
        // creates a vector with the lines in the nomFichier text file
        // lines are made up of fields separated by separators
        // if separator=null, the line forms a single field
        // only fields whose indexes are in tChampsVoulus are desired
        // indexes start at 1
        // if tChampsvoulus=null or empty, all fields are taken
        // if strict=true, all desired fields must be present
        // if this is not the case, the line is not stored and its index
        // is placed in the vector lignesErronees
        // white lines are ignored
        // as well as lines beginning with tagCommentaire if tagCommentaire != null

Die Klasse hätte die folgenden privaten Attribute:

        private int erreur=0;
        private Vector lignesErronees=null;

Das Attribut „erreur“ wird vom vorherigen Konstruktor mit den folgenden Werten gesetzt:

0: Die Konstruktion war erfolgreich

1: Die zu verarbeitende Datei konnte nicht geöffnet werden

4: Es fehlen einige erforderliche Felder, obwohl strict=true

8: Bei der Verarbeitung der Datei ist ein E/A-Fehler aufgetreten

Das Attribut lignesErronees ist ein Vektor, dessen Elemente die Nummern der fehlerhaften Zeilen in Form von Zeichenfolgen enthalten. Eine Zeile gilt als fehlerhaft, wenn sie bei strict=true die angeforderten Felder nicht bereitstellen kann.

Die Klasse verfügt außerdem über zwei Methoden:

    public int getErreur()

die den Wert des privaten Attributs „error“ zurückgibt.

    public String identite(){

die den Wert des Objekts in der Form (Fehler, Element 1, Element 2 …,(l1,l2,…)) anzeigt, wobei die Elemente i die Elemente des aus der Datei konstruierten Vektors sind und li die Nummern der fehlerhaften Zeilen sind.

Hier ist ein Beispieltest:


import java.io.*;
//import filetovector;
 
public class test2{
  public static void main(String arg[]){
    int[] T1={1,3};
    System.out.println(new filetovector("data.txt",":",T1,false,"#").identite());
    System.out.println(new filetovector("data.txt",":",T1,true,"#").identite());
    System.out.println(new filetovector("data.txt","",T1,false,"#").identite());
    System.out.println(new filetovector("data.txt",null,T1,false,"#").identite());
    int[] T2=null;
    System.out.println(new filetovector("data.txt",":",T2,false,"#").identite());
    System.out.println(new filetovector("data.txt",":",T2,false,"").identite());
    int[] T3=new int[0];
    System.out.println(new filetovector("data.txt",":",T3,false,null).identite());
  }
}

Ausführungsergebnisse:

[0,(0,a,c) (0,1,3) (0,azerty,cvf) (0,s)]
[4,(0,a,c) (0,1,3) (0,azerty,cvf),[5]]
[0,(0,a:b:c:d:e) (0,1 :2 : 3:  4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a:b:c:d:e) (0,1 :2 : 3:  4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]

Einige Tipps

  1. Die Textdatei wird zeilenweise verarbeitet. Die Zeile wird mithilfe der zuvor besprochenen stringtovector-Klasse in Felder aufgeteilt.

  2. Die Elemente des aus der Textdatei erstellten Vektors sind daher Objekte vom Typ „stringtovector“.

  3. Die Methode identite von filetovector kann sich auf die Methode stringtovector.identite() stützen, um ihre Elemente anzuzeigen, sowie auf die Methode Vector.toString(), um die Nummern fehlerhafter Zeilen anzuzeigen.

4.12.5. Übung 5

Wir möchten der Klasse „filetovector“ den folgenden Konstruktor hinzufügen:


    public filetovector(String nomFichier, String separateur, String sChampsVoulus,
            boolean strict, String tagCommentaire){
        
        // creates a vector with the lines in the nomFichier text file
        // lines are made up of fields separated by separators
        // if separator=null, the line forms a single field
        // only fields whose indexes are in tChampsVoulus are desired
        // indexes start 1
        // if sChampsvoulus=null or empty, all fields are taken
        // if strict=true, all desired fields must be present
        // if this is not the case, the line is not stored and its index
        // is placed in the vector lignesErronees
        // white lines are ignored
        // as well as lines beginning with tagCommentaire if tagCommentaire != null

Die Liste der Indizes für die Pflichtfelder liegt nun in einer Zeichenkette (String) statt in einem Array von Ganzzahlen vor.

Das private Fehlerattribut kann einen zusätzlichen Wert haben:

2: Die Zeichenkette der gewünschten Feldindizes ist falsch

Hier ist ein Beispieltest:


import java.io.*;
//import filetovector;
 
public class test1{
  public static void main(String arg[]){
    System.out.println(new filetovector("data.txt",":","1 3",false,"#").identite());
    System.out.println(new filetovector("data.txt",":","1 3",true,"#").identite());
    System.out.println(new filetovector("data.txt","","1 3",false,"#").identite());
    System.out.println(new filetovector("data.txt",null," 1 3",false,"#").identite());
    String S2=null;
    System.out.println(new filetovector("data.txt",":",S2,false,"#").identite());
    System.out.println(new filetovector("data.txt",":",S2,false,"").identite());
    String S3="";
    System.out.println(new filetovector("data.txt",":",S3,false,null).identite());
  }
}

Ergebnisse:

[0,(0,a,c) (0,1,3) (0,azerty,cvf) (0,s)][4,(0,a,c) (0,1,3) (0,azerty,cvf),[5]]
[0,(0,a:b:c:d:e) (0,1 :2 : 3:  4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a:b:c:d:e) (0,1 :2 : 3:  4: 5) (0,azerty : 1 : cvf : fff: qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# commentaire) (0,azerty,1,cvf,fff,qqqq) (0,s)]

Einige Tipps

  1. Wir wandeln die Zeichenkette sChampsVoulus in ein Array von Ganzzahlen tChampVoulus um, um sie wieder in den Fall des vorherigen Konstruktors zu bringen.