4. Häufig verwendete Klassen
In diesem Kapitel stellen wir eine Reihe häufig verwendeter Java-Klassen vor. Diese verfügen über zahlreiche Attribute, Methoden und Konstruktoren. Wir stellen jeweils nur einen kleinen Teil der Klassen vor. Ausführliche Informationen dazu finden Sie in der Java-Hilfe, die wir nun vorstellen.
4.1. Die Dokumentation
Wenn Sie das JDK von Sun im Ordner <jdk> installiert haben, finden Sie die Dokumentation im Ordner <jdk>\docs:

Manchmal hat man ein jdk, jedoch ohne Dokumentation. Diese ist auf der Website von Sun unter http://www.sun.com zu finden. Im Ordner docs befindet sich eine Datei index.html, die den Ausgangspunkt für die Hilfe zu JDK bildet:


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

Folgen wir dem Link „Java 2 Platform“ API:

Diese Seite ist der eigentliche Ausgangspunkt der Dokumentation zu den Klassen. Man kann eine Verknüpfung darauf erstellen, um schnell darauf zugreifen zu können. Die Datei URL befindet sich unter <jdk>\docs\api\index.html. Dort finden sich Links zu Hunderten von Java-Klassen des JDK. Zu Beginn besteht die größte Schwierigkeit darin, zu verstehen, was diese verschiedenen Klassen bewirken. Zunächst ist diese Hilfe daher nur dann von Nutzen, wenn man den Namen der Klasse kennt, zu der man Informationen sucht. Man kann sich auch von den Klassennamen leiten lassen, die in der Regel die Funktion der Klasse andeuten.
Nehmen wir ein Beispiel und suchen wir nach Informationen zur Klasse Vector, die ein dynamisches Array implementiert. Dazu muss man lediglich in der Klassenliste im linken Rahmen den Link zur Klasse Vector suchen:

und auf den Link zu klicken, um die Definition der Klasse anzuzeigen:

Dort findet man
- die Hierarchie, in der sich die Klasse befindet, hier java.util.Vector
- die Liste der Felder (Attribute) der Klasse
- die Liste der Konstruktoren
- die Liste der Methoden
Im Folgenden stellen wir verschiedene Klassen vor. Wir empfehlen dem Leser, stets die vollständige Definition der verwendeten Klassen zu überprüfen.
4.2. Die Testklassen
In den folgenden Beispielen werden gelegentlich die Klassen personne und enseignant verwendet. Wir möchten hier noch einmal auf deren Definition hinweisen.
public class personne{
// Nachname, Vorname, Alter
private String prenom;
private String nom;
private int age;
// Konstruktor 1
public personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
}
// Konstruktor 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+")";
}
// Zubehör
public String getPrenom(){
return prenom;
}
public String getNom(){
return nom;
}
public int getAge(){
return age;
}
//Modifikatoren
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 enseignant ist von der Klasse personne abgeleitet und wie folgt definiert:
class enseignant extends personne{
// Attribute
private int section;
// Konstruktor
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 etudiant verwenden, die von der Klasse personne 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 Klasse „String“
Die Klasse String repräsentiert Zeichenfolgen. Sei nom eine Zeichenfolgenvariable:
String name;
nom ist eine Referenz auf ein noch nicht initialisiertes Objekt. Es gibt zwei Möglichkeiten, es zu initialisieren:
name = „Pferd“ oder name = new String(„Pferd“)
Beide Methoden sind gleichwertig. Wenn man später name="Fisch" schreibt, verweist nom dann auf ein neues Objekt. Das alte Objekt *String("cheval")* geht verloren und der von ihm belegte Speicherplatz wird freigegeben.
Die Klasse String verfügt über zahlreiche Attribute und Methoden. Hier sind einige davon:
public char charAt(int i) | gibt das Zeichen i der Zeichenkette zurück, wobei das erste Zeichen den Index 0 hat. Somit ist String("Pferd").charAt(3) gleich 'v' |
public int compareTo(Zeichenkette2) | chaine1.compareTo(Zeichenkette2) vergleicht Zeichenkette1 mit Zeichenkette2 und gibt 0 zurück, wenn Zeichenkette1 = Zeichenkette2 ist, 1, wenn Zeichenkette1 > Zeichenkette2 ist, und -1, wenn Zeichenkette1 < Zeichenkette2 ist |
public boolean equals(Object anObject) | chaine1.equals(Zeichenkette2) gibt „wahr“ zurück, wenn Zeichenkette1 = Zeichenkette2 ist, andernfalls „falsch“ |
public String toLowerCase() | chaine1.toLowerCase() wandelt „Zeichenkette1“ in Kleinbuchstaben um |
public String toUpperCase() | chaine1.toUpperCase() wandelt „Zeichenfolge1“ in Großbuchstaben um |
public String trim() | chaine1.trim() entfernt die führenden und abschließenden Leerzeichen aus „chaine1“ |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) gibt die Zeichenfolge „ape“ zurück |
public char[] toCharArray() | ermöglicht es, die Zeichen der Zeichenkette in ein Zeichenarray zu speichern |
int length() | Anzahl der Zeichen in der Zeichenkette |
int indexOf(String Zeichenkette2) | gibt die erste Position von chaine2 in der aktuellen Zeichenkette zurück oder -1, wenn chaine2 nicht vorhanden ist |
int indexOf(String Zeichenfolge2, int startIndex) | gibt die erste Position von chaine2 in der aktuellen Zeichenkette zurück oder -1, wenn chaine2 nicht vorhanden ist. Die Suche beginnt ab dem Zeichen mit der Nummer startIndex. |
int lastIndexOf(String Zeichenfolge2) | gibt die letzte Position von chaine2 in der aktuellen Zeichenkette zurück oder -1, wenn chaine2 nicht vorhanden ist |
boolean startsWith(String Zeichenfolge2) | gibt „wahr“ zurück, wenn die aktuelle Zeichenkette mit chaine2 beginnt |
boolean endsWith(String Zeichenkette2) | Gibt „wahr“ zurück, wenn die aktuelle Zeichenkette mit chaine2 endet |
boolean matches(String regex) | gibt „true“ zurück, wenn die aktuelle Zeichenfolge dem regulären Ausdruck regex entspricht. |
String[] split(String regex) | Die aktuelle Zeichenkette besteht aus Feldern, die durch eine Zeichenfolge getrennt sind, die durch den regulären Ausdruck regex modelliert wird. Mit der Methode split können die Felder in einem Array abgerufen werden. |
String replace(char oldChar, char newChar) | ersetzt in der aktuellen Zeichenkette das Zeichen oldChar durch das Zeichen newChar. |
Hier ist ein Beispielprogramm:
// Importe
import java.io.*;
public class string1{
// eine Beispielklasse
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]+"]");
}//für
affiche("(\" abc \").trim()=["+" abc ".trim()+"]");
}//Main
// zeigt an
public static void affiche(String msg){
// zeigt eine Meldung an
System.out.println(msg);
}//zeigt an
}//Klasse
und die erzielten 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 Klasse „Vector“
Ein Vektor ist ein dynamisches Array, dessen Elemente Verweise auf Objekte sind. Es handelt sich also um ein Array von Objekten, dessen Größe sich im Laufe der Zeit ändern kann, was bei den bisher behandelten statischen Arrays nicht möglich ist. Hier sind einige Felder, Konstruktoren und Methoden dieser Klasse:
public Vector() | Erstellt einen leeren Vektor |
public final int size() | Anzahl der Elemente des Vektors |
public final void addElement(Object obj) | fügt das durch obj referenzierte Objekt zum Vektor hinzu |
public final Object elementAt(int index) | Referenz auf das Objekt mit der Nummer index im Array – die Indizes beginnen bei 0 |
public final Enumeration elements() | die Gesamtheit der Elemente des Vektors in Form einer Enumeration |
public final Object firstElement() | Referenz auf das erste Element des Vektors |
public final Object lastElement() | Referenz auf das letzte Element des Vektors |
public final boolean isEmpty() | gibt „true“ zurück, wenn der Vektor leer ist |
public final void removeElementAt(int index) | Entfernt das Element mit dem Index index |
public final void removeAllElements() | leert das Array von allen Elementen |
public final String toString() | gibt eine Identifikationszeichenfolge des Vektors zurück |
Hier ist ein Testprogramm:
// die importierten Klassen
import java.util.*;
public class test1{
// das Hauptprogramm main – static – Klassenmethode
public static void main(String arg[]){
// Erstellung von Klasseninstanzen
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());
// Polymorphismus
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// ein Vektor
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());
}
} // Ende von main
}// Ende der Klasse
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)
Im weiteren Verlauf werden wir den Vorgang des Kompilierens und Ausführens der Testprogramme nicht mehr wiederholen. Es reicht aus, die oben beschriebenen Schritte zu wiederholen.
4.5. Die Klasse ArrayList
Die Klasse ArrayList entspricht der Klasse Vector. Sie unterscheidet sich von dieser im Wesentlichen nur dann, wenn sie gleichzeitig von mehreren Ausführungsthreads genutzt wird. Die Methoden zur Synchronisation der Threads für den Zugriff auf ein Vector oder ein ArrayList unterscheiden sich. Abgesehen von diesem Fall kann man das eine oder das andere beliebig verwenden. Hier sind einige Felder, Konstruktoren oder 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 zur Liste hinzu |
void add(int index, Object obj) | fügt das Objekt, auf das obj verweist, an der Position index in das Array ein |
Object get(int index) | Referenz auf das Objekt Nr. index im Array – die Indizes beginnen bei 0 |
boolean isEmpty() | gibt „wahr“ zurück, wenn das Array leer ist |
void remove(int index) | entfernt das Element mit dem Index index |
void clear() | leert das Array von allen Elementen |
Object[] toArray() | wandelt das dynamische Array in ein klassisches Array um |
String toString() | gibt eine Identifikationszeichenfolge des Arrays zurück |
Hier ist ein Testprogramm:
// importierte Klassen
import java.util.*;
public class test1{
// das Hauptprogramm main – static – Klassenmethode
public static void main(String arg[]){
// Erstellung von Klasseninstanzen
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);
// Polymorphismus
personne p2=(personne)en;
System.out.println("p2="+p2);
personne p3=(personne)et;
System.out.println("p3="+p3);
// ein Vektor
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);
}
} // Ende von main
}// Ende der Klasse
Die Ergebnisse sind dieselben wie zuvor.
4.6. Die Klasse „Arrays“
Die Klasse java.util.Arrays bietet Zugriff auf statische Methoden, die verschiedene Operationen mit Arrays ermöglichen, insbesondere das Sortieren und die Suche nach Elementen. Hier sind einige dieser Methoden:
static void sort(Array) | sortiert tableau unter Verwendung der impliziten Reihenfolge des Datentyps des Arrays, also Zahlen oder Zeichenfolgen. |
static void sort (Object[] Array, Comparator C) | sortiert das Array tableau und verwendet dabei die Vergleichsfunktion C zum Vergleichen der Elemente |
static int binarySearch(array, element) | gibt die Position von élément in tableau zurück oder andernfalls einen Wert <0. Das Array muss zuvor sortiert sein. |
static int binarySearch(Object[] array, Object element, Comparator C) | Wie oben, verwendet jedoch die Vergleichsfunktion C zum Vergleichen zweier Elemente des Arrays. |
Hier ein erstes Beispiel:
import java.util.*;
public class sort2 implements Comparator{
// eine interne private Klasse
private class personne{
private String nom;
private int age;
public personne(String nom, int age){
this.nom=nom; // Name der Person
this.age=age; // ihr Alter
}
// Alter abrufen
public int getAge(){
return age;
}
// Identität der Person
public String toString(){
return ("["+nom+","+age+"]");
}
}; // Klasse „Person“
// Hersteller
public sort2() {
// ein Personenarray
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// Sortierung des Personenarrays
Arrays.sort(amis,this);
// Überprüfung
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//Konstruktor
// die Funktion, die Personen vergleicht
public int compare(Object o1, Object o2){
// muss
// -1 zurückgeben, wenn o1 „kleiner als“ o2 ist
// 0, wenn o1 „gleich“ o2
// +1, wenn o1 „größer als“ o2 ist
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;
}//vergleicht
// Testfunktion
public static void main(String[] arg){
new sort2();
}//Hand
}//Klasse
Sehen wir uns dieses Programm einmal an. Die Funktion „main“ erstellt ein Objekt vom Typ „sort2“. Der Konstruktor der Klasse „sort2“ sieht wie folgt aus:
// Hersteller
public sort2() {
// eine Personentabelle
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// Sortierung der Personentabelle
Arrays.sort(amis,this);
// Überprüfung
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//Hersteller
Das zu sortierende Array ist ein Array von Objekten vom Typ personne. Die Klasse personne ist privat (private) innerhalb der Klasse sort2 definiert. Die statische Methode sort der Klasse Arrays weiß nicht, wie ein Array von Objekten vom Typ personne sortiert werden soll, daher muss hier die Form void sort(Object[] obj, Comparator C) verwendet werden. Comparator ist eine Schnittstelle, die nur eine Methode definiert:
und die den Wert 0 zurückgeben muss: wenn o1 = o2, -1, wenn o1 < o2, +1, wenn o1 > o2. Im Prototyp void sort(Object[] obj, Comparator C) muss das zweite Argument C ein Objekt sein, das die Schnittstelle Comparator implementiert. Im Konstruktor sort2 wurde das aktuelle Objekt this ausgewählt:
Dies erfordert zwei Schritte:
- angeben, dass die Klasse sort2 die Schnittstelle Comparator implementiert
- die Funktion compare in die Klasse sort2 schreiben.
Diese lautet wie folgt:
// die Funktion, die Personen vergleicht
public int compare(Object o1, Object o2){
// muss Folgendes zurückgeben
// -1 zurückgeben, wenn o1 „kleiner als“ o2 ist
// 0, wenn o1 „gleich“ o2 ist
// +1, wenn o1 „größer als“ o2 ist
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;
}//vergleicht
Um zwei Objekte personne zu vergleichen, wird hier das Alter herangezogen (man hätte auch den Namen verwenden können).
Die Ergebnisse der Ausführung lauten wie folgt:
Man hätte auch anders vorgehen können, um die Schnittstelle Comparator zu implementieren:
import java.util.*;
public class sort2 {
// eine interne private Klasse
private class personne{
…….
}; // Klasse „Person“
// Konstruktor
public sort2() {
// ein Array von Personen
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// Sortieren des Personen-Arrays
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//Vergleich
}//Klasse
);
// Überprüfung
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//Konstruktor
// die Funktion, die Personen vergleicht
public int compare1(Object o1, Object o2){
// muss
// -1 zurückgeben, wenn o1 „kleiner als“ o2 ist
// 0, wenn o1 „gleich“ o2
// +1, wenn o1 „größer als“ o2 ist
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;
}//vergleicht1
// main
public static void main(String[] arg){
new sort2();
}//main
}//Klasse
Die Sortieranweisung lautet nun wie folgt:
// Sortierung des Personenarrays
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//vergleichen
}//Klasse
);
Der zweite Parameter der Methode sort muss ein Objekt sein, das die Schnittstelle Comparator implementiert. Hier erstellen wir ein solches Objekt mit new java.util.Comparator(), und der nachfolgende Text {…} definiert die Klasse, von der ein Objekt erstellt wird. Man bezeichnet dies als anonyme Klasse, da sie keinen Namen trägt. In dieser anonymen Klasse, die die Schnittstelle Comparator implementieren muss, definieren wir die Methode compare dieser Schnittstelle. Diese ruft lediglich die Methode compare1 der Klasse sort2 auf. Damit sind wir wieder beim vorherigen Fall angelangt.
Die Klasse sort2 implementiert die Schnittstelle Comparator nicht mehr. Daher lautet ihre Deklaration nun:
Nun testen wir die Methode binarySearch der Klasse Arrays anhand des folgenden Beispiels:
import java.util.*;
public class sort4 {
// eine interne private Klasse
private class personne{
// Attribute
private String nom;
private int age;
// Konstruktor
public personne(String nom, int age){
this.nom=nom; // Name der Person
this.age=age; // ihr Alter
}
// den Namen abrufen
public String getNom(){
return nom;
}
// Alter abrufen
public int getAge(){
return age;
}
// Identität der Person
public String toString(){
return ("["+nom+","+age+"]");
}
}; // Personenklasse
// Hersteller
public sort4() {
// ein Array von Personen
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// Vergleichsoperatoren
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//vergleicht
}//Klasse
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//vergleicht
}//sortiert
;
// Sortierung der Personentabelle
Arrays.sort(amis,comparateur1);
// Überprüfung
for(int i=0;i<3;i++)
System.out.println(amis[i]);
// Suchen
cherche("milou",amis,comparateur2);
cherche("xx",amis,comparateur2);
}//Ersteller
// die Funktion zum Vergleichen von Personen
public int compare1(Object o1, Object o2){
// muss
// -1 zurückgeben, wenn o1 „kleiner als“ o2 ist
// 0, wenn o1 „gleich“ o2 ist
// +1, wenn o1 „größer als“ o2 ist
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;
}//vergleicht1
// die Funktion, die eine Person mit einem Namen vergleicht
public int compare2(Object o1, Object o2){
// o1 ist eine Person
// o2 ist ein String, der Name „nom2“ einer Person
// muss Folgendes zurückgeben
// -1 zurückgeben, wenn o1.nom „kleiner als“ nom2 ist
// 0, wenn o1.nom „gleich“ nom2 ist
// +1, wenn o1.nom „größer als“ nom2 ist
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//Vergleich2
public void cherche(String ami,personne[] amis, Comparator comparateur){
// sucht Freund in der Freundesliste
int position=Arrays.binarySearch(amis,ami,comparateur);
// gefunden?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//sucht
// Hand
public static void main(String[] arg){
new sort4();
}//Hand
}//Klasse
Hier sind wir etwas anders vorgegangen als in den vorherigen Beispielen. Die beiden Objekte Comparator, die für die Methoden sort und binarySearch benötigt werden, wurden angelegt und den Variablen comparateur1 und comparateur2 zugewiesen.
// Vergleicher
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//vergleicht
}//Klasse
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//Vergleich
}//Klasse
;
Im Konstruktor von sort4 wird zweimal eine dichotomische Suche in der Tabelle amis durchgeführt:
Die Methode cherche erhält alle Parameter, die sie benötigt, um die Methode binarySearch aufzurufen:
public void cherche(String ami,personne[] amis, Comparator comparateur){
// Freund in der Freundesliste suchen
int position=Arrays.binarySearch(amis,ami,comparateur);
// gefunden?
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//sucht
Die Methode binarySearch arbeitet mit dem Komparator comparateur2 zusammen, der wiederum die Methode compare2 der Klasse sort4 aufruft. Die Methode rend gibt die Position des gesuchten Namens im Array zurück, sofern dieser vorhanden ist, andernfalls eine Zahl <0. Die Methode compare2 dient dazu, ein Objekt vom Typ personne mit einem Namen vom Typ String zu vergleichen.
// die Funktion, die eine Person mit einem Namen vergleicht
public int compare2(Object o1, Object o2){
// o1 ist eine Person
// o2 ist ein String, der Name „nom2“ einer Person
// muss Folgendes zurückgeben
// -1, wenn o1.nom „kleiner als“ Name2
// 0, wenn o1.nom „gleich“ Name2
// +1, wenn o1.nom „größer als“ Name2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//vergleiche2
Im Gegensatz zur Methode sort erhält die Methode binarySearch nicht zwei Objekte vom Typ personne, sondern ein Objekt vom Typ personne und ein Objekt vom Typ String in dieser Reihenfolge. Der erste Parameter ist ein Element des Arrays amis, der zweite der Name der gesuchten Person.
4.7. Die Klasse „Enumeration“
Enumeration ist eine Schnittstelle und keine Klasse. Sie verfügt über folgende Methoden:
public abstract boolean hasMoreElements() | gibt „true“ zurück, wenn die Enumeration noch Elemente enthält |
public abstract Object nextElement() | gibt die Referenz auf das nächste Element der Enumeration zurück |
Wie nutzt man eine Enumeration? Im Allgemeinen so:
Enumeration e=… // ein Aufzählungsobjekt wird abgerufen
while(e.hasMoreElements()){
// das Element e.nextElement() auswerten
}
Hier ein Beispiel:
// die importierten Klassen
import java.util.*;
public class test1{
// Das Hauptprogramm „main“ – statische Klassenmethode
public static void main(String arg[]){
// Erstellung von Klasseninstanzen
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());
// Polymorphismus
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// ein Vektor
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());
}
// eine Aufzählung
Enumeration E=V.elements();
i=0;
while(E.hasMoreElements()){
p2=(personne) E.nextElement();
System.out.println("V["+i+"]="+p2.toString());
i++;
}
}// Ende von main
}//Ende der Klasse
Man erhält folgende Ergebnisse:
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 Klasse „Hashtable“
Mit der Klasse Hashtable lässt sich ein Wörterbuch implementieren. Ein Wörterbuch kann man sich als zweispaltiges Array vorstellen:
Schlüssel | Wert |
Schlüssel1 | Wert1 |
Schlüssel2 | Wert2 |
.. | ... |
Die Schlüssel sind eindeutig, c.a.d. Es kann also keine zwei identischen Schlüssel geben. Die wichtigsten Methoden und Eigenschaften der Klasse „Hashtable“ sind die folgenden:
public Hashtable() | Konstruktor – erstellt ein leeres Hash-Wörterbuch |
public int size() | Anzahl der Elemente im Hash-Table – 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 Objekt ab, das dem Schlüssel key zugeordnet ist, oder null, falls der Schlüssel key nicht existiert |
public boolean containsKey(Object key) | wahr, wenn der Schlüssel key im Wörterbuch vorhanden ist |
public boolean contains(Object value) | wahr, 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 Paar (Schlüssel, Wert), wobei Schlüssel=key |
public String toString() | identifiziert das Wörterbuch |
Hier ein Beispiel:
// die importierten Klassen
import java.util.*;
public class test1{
// das Hauptprogramm main – static – Klassenmethode
public static void main(String arg[]){
// Erstellung von Klasseninstanzen
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());
// Polymorphismus
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// ein 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++;
}
}//Ende von main
}//Ende der Klasse
Die folgenden Ergebnisse wurden erzielt:
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ötigt man einen Schreibstrom. Dazu kann die Klasse FileWriter verwendet werden. Die häufig verwendeten Konstruktoren sind die folgenden:
FileWriter(String fileName) | erstellt die Datei mit dem Namen fileName – anschließend kann in diese geschrieben werden – eine eventuell bereits vorhandene Datei mit demselben Namen wird überschrieben |
FileWriter(String fileName, boolean append) | dasselbe – eine eventuell bereits 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 es sich, die Klasse PrintWriter zu verwenden, deren häufig verwendete Konstruktoren wie folgt lauten:
PrintWriter(Writer out) | Das Argument ist vom Typ Writer oder c.a.d. Ein Schreibstrom (in eine Datei, ins Netzwerk, …) |
PrintWriter(Writer out, boolean autoflush) | Das Gleiche. Das zweite Argument steuert die Pufferung der Zeilen. Wenn es auf „false“ gesetzt ist (Standardwert), werden die in die Datei geschriebenen Zeilen zunächst in einen Speicherpuffer geschrieben. Sobald dieser voll ist, wird der Inhalt in die Datei geschrieben. Dies verbessert den Festplattenzugriff. Allerdings ist dieses Verhalten manchmal unerwünscht, insbesondere beim Schreiben ins Netzwerk. |
Die nützlichen Methoden der Klasse PrintWriter sind die folgenden:
void print(Type T) | schreibt den Wert T (String, int, …) |
void println(Type T) | ebenso, jedoch mit einem Zeilenendezeichen am Ende |
void flush() | leert den Puffer, wenn man sich nicht im Autoflush-Modus befindet |
void close() | schließt den Schreibstrom |
Hier ist ein Programm, das einige Zeilen in eine Textdatei schreibt:
// Importe
import java.io.*;
public class ecrire{
public static void main(String[] arg){
// Datei öffnen
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// Schreiben in die Datei
try{
fic.println("Jean,Dupont,27");
fic.println("Pauline,Garcia,24");
fic.println("Gilles,Dumond,56");
} catch (Exception e){
Erreur(e,3);
}
// Datei schließen
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// Ende der Hauptfunktion
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Fehler
}//Klasse
Die bei der Ausführung erzeugte Datei out lautet wie folgt:
4.9.2. Lesen
Um den Inhalt einer Datei zu lesen, benötigt man einen mit der Datei verknüpften Lesestrom. Dazu kann man die Klasse FileReader und den folgenden Konstruktor verwenden:
FileReader(String Dateiname) | Ö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 Einlesen aus einer Datei, die von der Klasse Reader geerbt wurden. Um Textzeilen aus einer Textdatei einzulesen, empfiehlt es sich, die Klasse BufferedReader mit dem folgenden Konstruktor zu verwenden:
BufferedReader(Reader in) | öffnet einen gepufferten Lesestrom aus einem Eingabestrom vom Typ in. Dieser Strom vom Typ Reader kann von der Tastatur, aus einer Datei, aus dem Netzwerk usw. stammen. |
Die nützlichen Methoden der Klasse BufferedReader sind die folgenden:
int read() | liest ein Zeichen |
String readLine() | liest eine Textzeile |
int read(char[] buffer, int offset, int taille) | liest taille Zeichen aus der Datei und speichert sie ab der Position offset im Array buffer. |
void close() | schließt den Lesestrom |
Hier ist ein Programm, das den Inhalt der zuvor erstellten Datei liest:
// importierte Klassen
import java.util.*;
import java.io.*;
public class lire{
public static void main(String[] arg){
personne p=null;
// Datei öffnen
BufferedReader IN=null;
try{
IN=new BufferedReader(new FileReader("out"));
} catch (Exception e){
Erreur(e,1);
}
// Daten
String ligne=null;
String[] champs=null;
String prenom=null;
String nom=null;
int age=0;
// Behandlung eventueller Fehler
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));
}// Ende der while-Schleife
} catch (Exception e){
Erreur(e,2);
}
// Datei schließen
try{
IN.close();
} catch (Exception e){
Erreur(e,3);
}
}// Ende von „main“
// Fehler
public static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}
}// Ende der Klasse
Die Ausführung des Programms liefert folgende Ergebnisse:
4.9.3. Speichern eines Personenobjekts
Wir wenden das soeben Gelernte an, um der Klasse personne eine Methode zur Verfügung zu stellen, mit der die Attribute einer Person in einer Datei gespeichert werden können. Wir fügen die Methode sauveAttributs in die Definition der Klasse personne ein:
// ------------------------------
// in Textdatei speichern
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
Vor der Definition der Klasse personne darf nicht vergessen werden, das Paket java.io zu importieren:
Die Methode sauveAttributs erhält als einzigen Parameter den Datenstrom PrintWriter, in den sie schreiben soll. Ein Testprogramm könnte wie folgt aussehen:
// Importe
import java.io.*;
// Person importieren;
public class sauver{
public static void main(String[] arg){
// Datei öffnen
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// Schreiben in die Datei
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);
}
// Datei schließen
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// Ende main
// Fehler
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//Fehler
}//Klasse
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 die Verwaltung von Binärdateien, insbesondere solcher mit fester Struktur, wie sie aus der Programmiersprache C/C++ bekannt sind. Hier sind einige nützliche Methoden und Konstruktoren:
RandomAccessFile(String Dateiname, String Modus) | Konstruktor – öffnet die angegebene Datei im angegebenen Modus. Dieser kann folgende Werte annehmen: r: Öffnen zum Lesen rw: Öffnen zum Lesen und Schreiben |
void writeTTT(TTT Wert) | Schreibt den Wert in die Datei. TTT steht für den Werttyp. Die Speicherdarstellung des Werts wird unverändert in die Datei geschrieben. So finden sich writeBoolean, writeByte, writeInt, writeDouble, writeLong, writeFloat, ... Um eine Zeichenkette zu schreiben, verwendet man writeBytes(String Zeichenkette). |
TTT readTTT() | liest einen Wert vom Typ TTT und gibt ihn zurück. So gibt es readBoolean, readByte, readInt, readDouble, readLong, readFloat, ... 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 das Byte pos |
4.10.2. Die Klasse „article“
Alle folgenden Beispiele verwenden die folgende Klasse article:
// die Artikelstruktur
private static class article{
// Die Struktur wird definiert
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Artikelklasse
Die oben genannte Java-Klasse article entspricht der folgenden C-Struktur article
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//Struktur
Somit beschränken wir den Code auf 4 Zeichen und den Namen auf 20.
4.10.3. Einen Datensatz schreiben
Das folgende Programm schreibt einen Eintrag in eine Datei namens „data“:
// importierte Klassen
import java.io.*;
public class test1{
// testet das Schreiben einer Struktur (im Sinne von C) in eine Binärdatei
// die Artikel-Struktur
private static class article{
// Definition der Struktur
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Klasse „Artikel“
public static void main(String arg[]){
// Man definiert die Binärdatei, in der die Artikel gespeichert werden
RandomAccessFile fic=null;
// ein Artikel wird definiert
article art=new article();
art.code="a100";
art.nom="velo";
art.prix=1000.80;
art.stockActuel=100;
art.stockMinimum=10;
// Die Datei wird definiert
try{
fic=new RandomAccessFile("data","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//Try-Catch
// Es wird geschrieben
try{
ecrire(fic,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement",2);
}//try-catch
// Fertig
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}//main
// Schreibmethode
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// Code
fic.writeBytes(art.code);
// Der Name ist auf 20 Zeichen begrenzt
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);
// Preis
fic.writeDouble(art.prix);
// Lagerbestände
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// Schreiben beenden
// ------------------------Fehler
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// Ende des Fehlers
}// Ende der Klasse
Mit dem folgenden Programm können wir überprüfen, ob die Ausführung korrekt verlaufen ist.
4.10.4. Einen Datensatz lesen
// importierte Klassen
import java.io.*;
public class test2{
// testet das Schreiben einer Struktur (im Sinne von C) in eine Binärdatei
// die Struktur „article“
private static class article{
// Definition der Struktur
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Klasse „Artikel“
public static void main(String arg[]){
// Man definiert die Binärdatei, in der die Artikel gespeichert werden
RandomAccessFile fic=null;
// Die Datei wird zum Lesen geöffnet
try{
fic=new RandomAccessFile("data","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// Der einzige Artikel aus der Datei wird gelesen
article art=new article();
try{
lire(fic,art);
} catch (IOException E){
erreur("Erreur lors de la lecture de l'enregistrement",2);
}//try-catch
// Der gelesene Datensatz wird angezeigt
affiche(art);
// Fertig
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}// Ende manuell
// Lesemethode
public static void lire(RandomAccessFile fic, article art) throws IOException{
// Code lesen
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();
// Preis
art.prix=fic.readDouble();
// Bestände
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// Schreiben beenden
// ---------------------Anzeige
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);
}// Ende der Anzeige
// ------------------------Fehler
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// Ende Fehler
}// Ende der Klasse
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
Der vom Schreibprogramm geschriebene Datensatz wird korrekt abgerufen.
4.10.5. Konvertierung von Text in Binärdaten
Das folgende Programm ist eine Erweiterung des Programms zum Schreiben eines Datensatzes. Nun werden mehrere Datensätze in eine Binärdatei namens data.bin geschrieben. 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
// importierte Klassen
import java.io.*;
import java.util.*;
public class test3{
// Textdatei --> Binärdatei
// die Artikelstruktur
private static class article{
// Die Struktur wird definiert
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Artikelklasse
public static void main(String arg[]){
// Definition der Binärdatei, in der die Artikel gespeichert werden
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin",1);
}
// Die Daten werden aus einer Textdatei übernommen
BufferedReader dataTxt=null;
try{
dataTxt=new BufferedReader(new FileReader("data.txt"));
} catch (IOException E){
erreur("Impossible d'ouvrir le fichier data.txt",2);
}
// .txt-Datei --> .bin-Datei
String ligne=null;
String[] champs=null;
int numLigne=0;
String champ=null;
article art=new article(); // zu erstellender Artikel
try{
while((ligne=dataTxt.readLine())!=null){
// eine Zeile mit +
numLigne++;
// Aufteilung in Felder
champs=ligne.split(":");
// Es werden 5 Felder benötigt
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);
// Name, Vorname
art.nom=champs[1];
// Preis
try{
art.prix=Double.parseDouble(champs[2]);
} catch (Exception E){
erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
}
// aktueller Lagerbestand
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// aktueller Lagerbestand
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// Datensatz wird geschrieben
try{
ecrire(dataBin,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
}
// zur nächsten Zeile wechseln
}// Ende der while-Schleife
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// Fertig
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);
}
}// Ende von „main“
// Schreibmethode
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// Code
fic.writeBytes(art.code);
// Der Name ist auf 20 Zeichen begrenzt
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);
// der Preis
fic.writeDouble(art.prix);
// Lagerbestände
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// Schreiben beenden
// ------------------------Fehler
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// Ende des Fehlers
}// Ende der Klasse
Mit dem folgenden Programm lässt sich überprüfen, ob das Programm korrekt funktioniert hat.
4.10.6. Konvertierung von Binärcode in Text
Das folgende Programm liest den Inhalt der zuvor erstellten Binärdatei „data.bin“ ein und schreibt ihn in die Textdatei „data.text“. Wenn alles geklappt hat, sollte die Datei „data.text“ mit der Originaldatei „data.txt“ identisch sein.
// importierte Klassen
import java.io.*;
import java.util.*;
public class test5{
// Textdatei --> Binärdatei
// die Artikelstruktur
private static class article{
// Die Struktur wird definiert
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Artikelklasse
// main
public static void main(String arg[]){
// Definition der Binärdatei, in der die Artikel gespeichert werden
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// Die Daten werden in eine Textdatei geschrieben
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-Datei --> .text-Datei
article art=new article(); // zu erstellender Artikel
// Die Binärdatei wird ausgewertet
int numRecord=0;
long l=0; // Dateigröße
try{
l=dataBin.length();
} catch (IOException e){
erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
}
long pos=0; // aktuelle Position in der Datei
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
// solange das Dateiende noch nicht überschritten wurde
while(pos<l){
// aktuellen Datensatz lesen und verarbeiten
numRecord++;
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
affiche(art);
// Schreiben der entsprechenden Textzeile in dataTxt
dataTxt.println(art.code.trim()+":"+art.nom.trim()+":"+art.prix+":"+art.stockActuel+":"+art.stockMinimum);
// Weitermachen?
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
}// Ende der while-Schleife
// Fertig
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);
}
}// Ende von „main“
// Lesemethode
public static void lire(RandomAccessFile fic, article art) throws IOException{
// Code lesen
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();
// Preis
art.prix=fic.readDouble();
// Bestände
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// Schreiben beenden
// ---------------------Anzeige
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);
}// Ende der Anzeige
// ------------------------Fehler
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// Ende Fehler
}// Ende der Klasse
Hier ein Ausführungsbeispiel:
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 veranschaulicht die Möglichkeit, direkt auf die Datensätze einer Binärdatei zuzugreifen. Es zeigt den Datensatz der Datei data.bin an, dessen Nummer als Parameter übergeben wird, wobei der erste Datensatz die Nummer 1 trägt.
// importierte Klassen
import java.io.*;
import java.util.*;
public class test6{
// Textdatei --> Binärdatei
// die Artikelstruktur
private static class article{
// Die Struktur wird definiert
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//Artikelklasse
// main
public static void main(String[] args){
// Überprüfung der Argumente
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// Prüfung der Stammsatznummer
int numRecord=0;
try{
numRecord=Integer.parseInt(args[0]);
} catch(Exception e){
erreur(syntaxe+"\nNuméro de fiche incorrect",21);
}
// Die Binärdatei wird im Lesemodus geöffnet
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// Man springt zum gewünschten Datensatz
try{
dataBin.seek((numRecord-1)*40);
} catch (Exception e){
erreur("La fiche "+numRecord+" n'existe pas",23);
}
// Sie wird gelesen
article art=new article();
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
// Anzeige
affiche(art);
// Fertig
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}//try-catch
}// Ende von main
// Lesemethode
public static void lire(RandomAccessFile fic, article art) throws IOException{
// Code lesen
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();
// Preis
art.prix=fic.readDouble();
// Bestände
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// Schreiben beenden
// ---------------------Anzeige
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);
}// Ende der Anzeige
// ------------------------Fehler
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// Ende Fehler
}// Ende der Klasse
Hier sind einige Ausführungsbeispiele:
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. Reguläre Ausdrücke verwenden
4.11.1. Das Paket java.util.regex
Das Paket java.util.regex ermöglicht die Verwendung regulärer Ausdrücke. Mit diesen lässt sich das Format einer Zeichenkette überprüfen. So kann beispielsweise überprüft werden, ob eine Zeichenkette, die ein Datum darstellt, tatsächlich im Format TT/MM/JJ vorliegt. Dazu wird ein Muster verwendet und die Zeichenkette mit diesem Muster verglichen. In diesem Beispiel müssen j, m und a also Ziffern sein. Das Muster für ein gültiges Datumsformat lautet dann „\d\d/\d\d/\d\d“, wobei das Symbol \d eine Ziffer bezeichnet. Die folgenden Symbole können in einem Muster verwendet werden (Microsoft-Dokumentation):
Zeichen | Beschreibung |
\ | Markiert 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. |
^ | Entspricht dem Anfang der Eingabe. |
$ | Entspricht dem Ende der Eingabe. |
* | Entspricht dem vorhergehenden Zeichen nullmal oder mehrmals. So entspricht „zo*“ sowohl „z“ als auch „zoo“. |
+ | Entspricht dem vorhergehenden Zeichen ein- oder mehrmals. So entspricht „zo+“ beispielsweise „zoo“, aber nicht „z“. |
? | Entspricht dem vorhergehenden Zeichen null- oder einmal. Zum Beispiel entspricht „a?ve?“ dem Zeichen „ve“ in „lever“. |
. | Entspricht einem beliebigen einzelnen Zeichen, mit Ausnahme des Zeilenumbruchzeichens. |
(Vorlage) | Sucht nach „modèle“ und speichert die Übereinstimmung. Die entsprechende Teilzeichenfolge kann mithilfe von „Item [0]...[n]“ aus der erhaltenen Matches-Sammlung extrahiert werden. Um Übereinstimmungen mit Zeichen in Klammern ( ) zu finden, verwenden Sie „\(“ oder „\)“. |
x|y | Entspricht entweder x oder y. Beispielsweise entspricht „z|foot“ entweder „z“ oder „foot“. „(z|f)oo“ entspricht entweder „zoo“ oder „foo“. |
{n} | n ist eine nicht-negative ganze Zahl. Entspricht genau dem n-fachen des Zeichens. Beispielsweise entspricht „o{2}“ nicht dem „o“ in „Bob“, sondern den ersten beiden „o“ in „fooooot“. |
{n,} | n ist eine nicht-negative ganze Zahl. Entspricht mindestens dem n-fachen des Zeichens. Beispielsweise entspricht „o{2,}“ nicht dem „o“ in „Bob“, sondern allen „o“ in „fooooot“. „o{1,}“ entspricht „o+“ und „o{0,}“ entspricht „o*“. |
{n,m} | m und n sind nicht-negative ganze Zahlen. Entspricht mindestens n und höchstens m Mal dem Zeichen. Beispielsweise entspricht „o{1,3}“ den ersten drei „o“ in „foooooot“ und „o{0,1}“ entspricht „o?“. |
[xyz] | Zeichensatz. Entspricht einem der angegebenen Zeichen. Beispielsweise entspricht „[abc]“ dem Zeichen „a“ in „plat“. |
[^xyz] | Negativer Zeichensatz. Entspricht jedem nicht angegebenen Zeichen. Beispielsweise entspricht „[^abc]“ dem Zeichen „p“ in „plat“. |
[a-z] | Zeichenbereich. Entspricht jedem Zeichen in der angegebenen Zeichenfolge. Beispielsweise entspricht „[a-z]“ jedem Kleinbuchstaben zwischen „a“ und „z“. |
[^m-z] | Negativer Zeichenbereich. Entspricht jedem Zeichen, das nicht in der angegebenen Zeichenfolge enthalten ist. Beispielsweise entspricht „[^m-z]“ jedem Zeichen, das nicht zwischen „m“ und „z“ liegt. |
\b | Entspricht einer Wortgrenze, d. h. der Position zwischen einem Wort und einem Leerzeichen. Beispielsweise entspricht „er\b“ dem Wortteil „er“ in „lever“, nicht jedoch dem Wortteil „er“ in „verbe“. |
\B | Entspricht einer Grenze, die kein Wort darstellt. „en*t\B“ entspricht „ent“ in „bien entendu“. |
\d | Entspricht einem Zeichen, das eine Ziffer darstellt. Entspricht [0-9]. |
\D | Entspricht einem Zeichen, das keine Ziffer darstellt. Entspricht [^0-9]. |
\f | Entspricht einem Seitenumbruchzeichen. |
\n | Entspricht einem Zeilenumbruchzeichen. |
\r | Entspricht einem Wagenrücklaufzeichen. |
\s | Entspricht allen Leerzeichen, einschließlich Leerzeichen, Tabulatoren, Seitenumbrüchen usw. Entspricht „[ \f\n\r\t\v]“. |
\S | Entspricht jedem Nicht-Leerzeichen. Entspricht „[^ \f\n\r\t\v]“. |
\t | Entspricht einem Tabulatorzeichen. |
\v | Entspricht einem vertikalen Tabulatorzeichen. |
\w | Entspricht jedem Zeichen, das ein Wort darstellt und einen Unterstrich enthält. Entspricht „[A-Za-z0-9_]“. |
\W | Entspricht jedem Zeichen, das kein Wort darstellt. Entspricht „[^A-Za-z0-9_]“. |
\num | Entspricht num, wobei num eine positive ganze Zahl ist. Bezieht sich auf die gespeicherten Zuordnungen. Beispielsweise entspricht „(.)\1“ zwei aufeinanderfolgenden identischen Zeichen. |
|
Ein Element in einer Vorlage kann ein- oder mehrmals vorkommen. Betrachten wir einige Beispiele rund um das Symbol \d, das für eine Ziffer steht:
Vorlage | 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 das Modell vor, mit dem das erwartete Format einer Zeichenkette beschrieben werden kann:
gesuchte Zeichenfolge | Modell |
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 möglicherweise leere Folge von Leerzeichen | \s* |
eine vorzeichenlose Ganzzahl, der Leerzeichen vorangestellt oder nachgestellt sein können | \s*\d+\s* |
eine ganze Zahl, die vorzeichenbehaftet sein kann und der Leerzeichen vorangestellt oder nachgestellt sein 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 Leerräume vorangestellt oder nachgestellt sein können | \s*[+|]?\s*\d+(.\d*)?\s* |
eine Zeichenfolge, die das Wort „juste“ enthält | \bjuste\b |
Man kann angeben, an welcher Stelle in der Zeichenfolge nach dem Muster gesucht werden soll:
Muster | Bedeutung |
^Muster | Das Muster steht am Anfang der Zeichenfolge |
Muster$ | Das Muster beendet die Zeichenfolge |
^Muster$ | Das Muster beginnt und beendet die Zeichenfolge |
Muster | Das Muster wird überall in der Zeichenkette gesucht, beginnend am Anfang der Zeichenkette. |
gesuchte Zeichenfolge | 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 nur aus einem Wort besteht, dem gegebenenfalls Leerzeichen vorangestellt oder nachgestellt sind | ^\s*\w+\s*$ |
eine Zeichenfolge, die aus zwei Wörtern besteht, denen gegebenenfalls Leerzeichen vorangehen oder folgen | ^\s*\w+\s*\w+\s*$ |
eine Zeichenfolge, die das Wort „secret“ enthält | \bsecret\b |
Teilmengen eines Musters können „extrahiert“ werden. So lässt sich nicht nur überprüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht, sondern es können auch die Elemente aus dieser Zeichenfolge extrahiert werden, die den in Klammern gesetzten Teilmengen des Musters entsprechen. Wenn man also eine Zeichenfolge analysiert, die ein Datum im Format TT/MM/JJ enthält, und zusätzlich die Elemente TT, MM und JJ dieses Datums extrahieren möchte, verwendet man das Muster (\d\d)/(\d\d)/(\d\d).
4.11.2. Überprüfen, ob eine Zeichenkette einem vorgegebenen Muster entspricht
Mit der Klasse Pattern lässt sich überprüfen, ob eine Zeichenfolge einem vorgegebenen Muster entspricht. Dazu wird die statische Methode
mit: modèle: das zu prüfende Muster, chaine: die mit dem Muster zu vergleichende Zeichenfolge. Das Ergebnis ist der Boolesche Wert true, wenn die Zeichenfolge mit dem Muster übereinstimmt, andernfalls false.
Hier ein Beispiel:
import java.io.*;
import java.util.regex.*;
// Verwaltung regulärer Ausdrücke
public class regex1 {
public static void main(String[] args){
// ein regulärer Ausdruck als Vorlage
String modèle1="^\\s*\\d+\\s*$";
// Ein Exemplar mit dem Muster vergleichen
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
}//main
public static void affiche(String msg){
System.out.println(msg);
}//anzeigen
}//Klasse
und die Ausführungsergebnisse:
Es ist zu beachten, dass im Muster „^\s*\d+\s*$“ das Zeichen \ aufgrund der besonderen Interpretation dieses Zeichens durch Java doppelt geschrieben werden muss. Man schreibt also: String Muster1 = „^\\s*\\d+\\s*$“;
4.11.3. Alle Elemente einer Zeichenkette finden, die einem Muster entsprechen
Betrachten wir 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“ lassen sich die verschiedenen Vorkommen eines Musters in einer Zeichenkette abrufen. Die Klasse Pattern ist die Klasse, die reguläre Ausdrücke verwaltet. Ein regulärer Ausdruck, der mehr als einmal verwendet wird, muss „kompiliert“ werden. Dies beschleunigt die Suche nach dem Muster in den Zeichenketten. Die statische Methode compile übernimmt diese Aufgabe:
Sie nimmt die Zeichenkette des Musters als Parameter entgegen und gibt ein Objekt vom Typ Pattern zurück. Um das Muster eines Objekts vom Typ Pattern mit einer Zeichenkette zu vergleichen, wird die Klasse Matcher verwendet. Diese ermöglicht den Vergleich eines Musters mit einer Zeichenkette. Ausgehend von einem Objekt vom Typ Pattern lässt sich mit der Methode matcher ein Objekt vom Typ Matcher erzeugen:
input ist die Zeichenkette, die mit dem Muster verglichen werden soll.
Um also das Muster „\d+“ mit der Zeichenfolge „ 123 456 789 “ zu vergleichen, kann man ein Objekt vom Typ Matcher wie folgt erstellen:
Ausgehend vom vorherigen Objekt résultats können wir nun die verschiedenen Vorkommen des Musters in der Zeichenkette abrufen. Dazu verwenden wir die Methoden suivantes der Klasse Matcher:
Die Methode find sucht in der durchsuchten 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 ermittelt, seine Position mit der Methode start. Wenn wir also das vorherige Beispiel fortsetzen und alle Vorkommen des Musters „\d+“ in der Zeichenkette „ 123 456 789 “ anzeigen möchten, schreiben wir:
while(résultats.find()){
System.out.println("séquence " + résultats.group() + " trouvée en position " + résultats.start());
}//while
Mit der Methode reset lässt sich das Objekt Matcher auf den Anfang der mit dem Muster verglichenen Zeichenkette zurücksetzen. So findet die Methode find anschließend wieder das erste Vorkommen des Musters.
Hier ein vollständiges Beispiel:
import java.io.*;
import java.util.regex.*;
// Verwaltung regulärer Ausdrücke
public class regex2 {
public static void main(String[] args){
// mehrere Vorkommen des Musters im Exemplar
String modèle2="\\d+";
Pattern regex2=Pattern.compile(modèle2);
String exemplaire3=" 123 456 789";
// Suche nach Vorkommen des Musters im Exemplar
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);
}//zeigt an
}//Sortieren
Die Ergebnisse der Ausführung:
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 lässt sich nicht nur überprüfen, ob eine Zeichenfolge einem bestimmten Muster entspricht, sondern es können auch die Elemente aus dieser Zeichenfolge extrahiert werden, die den in Klammern gesetzten Teilmengen des Musters entsprechen. Wenn man also eine Zeichenfolge analysiert, die ein Datum im Format TT/MM/JJ enthält, und zusätzlich die Elemente TT, MM und JJ dieses Datums extrahieren möchte, verwendet man das Muster (\d\d)/(\d\d)/(\d\d).
Betrachten wir das folgende Beispiel:
import java.io.*;
import java.util.regex.*;
// Verwaltung regulärer Ausdrücke
public class regex3 {
public static void main(String[] args){
// Erfassung von Elementen im Modell
String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
Pattern regex3=Pattern.compile(modèle3);
String exemplaire4="Il est 18:05:49";
// Vorlagenprüfung
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// Das Exemplar entspricht der Vorlage
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// Gruppen werden angezeigt
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//for
}else{
// stimmt die Instanz nicht mit der Vorlage überein
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
}//Hauptbild
public static void affiche(String msg){
System.out.println(msg);
}//zeigt an
}//ordnet ein
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 Neuerung befindet sich im folgenden Codeabschnitt:
// Vorlagenprüfung
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// Das Exemplar entspricht der Vorlage
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// Gruppen werden angezeigt
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//für
}else{
// Das Exemplar entspricht nicht der Vorlage
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
Die Zeichenfolge exemplaire4 wird mithilfe der Methode find mit dem Muster regex3 verglichen. Dabei wird eine Instanz des Musters regex3 in der Zeichenfolge exemplaire4 gefunden. Enthält das Muster in Klammern eingeschlossene Teilmengen, so stehen diese über verschiedene Methoden der Klasse Matcher zur Verfügung:
public int groupCount()
public String group(int group)
public int start(int group)
Die Methode groupCount gibt die Anzahl der im Modell gefundenen Untergruppen zurück, und group(i) die Untergruppe Nr. i. Diese wird in der Zeichenkette an einer durch start(i) angegebenen Position gefunden. So zum Beispiel im folgenden Beispiel:
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
Beim ersten Aufruf der Methode find wird die Zeichenfolge 18:05:49 gefunden und automatisch werden die drei durch die Klammern im Muster definierten Teilmengen erstellt, nämlich 18, 05 und 49.
4.11.5. Ein Lernprogramm
Es ist manchmal eine echte Herausforderung, den regulären Ausdruck zu finden, mit dem wir überprüfen können, ob eine Zeichenfolge einem bestimmten Muster entspricht. Mit dem folgenden Programm können Sie üben. Es fragt nach einem Muster und einer Zeichenfolge und gibt dann an, ob die Zeichenfolge dem Muster entspricht oder nicht.
import java.io.*;
import java.util.regex.*;
// Verwaltung regulärer Ausdrücke
public class regex4 {
public static void main(String[] args){
// Daten
String modèle=null,chaine=null;
Pattern regex=null;
BufferedReader IN=null;
Matcher résultats=null;
int nbOccurrences=0;
// Fehlerbehandlung
try{
// Der Benutzer wird aufgefordert, die Vorlagen und Instanzen anzugeben, die mit dieser verglichen werden sollen
while(true){
// Eingabestrom
IN=new BufferedReader(new InputStreamReader(System.in));
// Die Vorlage wird abgefragt
System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
modèle=IN.readLine();
// Fertig?
if(modèle.trim().toLowerCase().equals("fin")) break;
// Der reguläre Ausdruck wird erstellt
regex=Pattern.compile(modèle);
// Der Benutzer wird gefragt, welche Exemplare mit dem Muster verglichen werden sollen
while(true){
System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
chaine=IN.readLine();
// Fertig?
if(chaine.trim().toLowerCase().equals("fin")) break;
// Das Matcher-Objekt wird erstellt
résultats=regex.matcher(chaine);
// Es wird nach Vorkommen des Musters gesucht
nbOccurrences=0;
while(résultats.find()){
// Es wurde ein Vorkommen gefunden
nbOccurrences++;
// es wird angezeigt
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// Anzeige der Unterelemente
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));
}//für j
}//if
// nächste Zeichenfolge
}//while(résultats.find())
// Wurde mindestens ein Vorkommen gefunden?
if(nbOccurrences==0){
System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
}//if
// nächstes Muster
}//while(true)
}//while(true)
}catch(Exception ex){
// Fehler
System.err.println("Erreur : "+ex.getMessage());
// Ende mit Fehler
System.exit(1);
}//try-catch
// Ende
System.exit(0);
}//Main
}//Klasse
Hier 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 Methode „split“ der Klasse „Pattern“
Betrachten wir eine Zeichenkette, die aus Feldern besteht, die durch eine Trennzeichenfolge getrennt sind, die mithilfe eines regulären Ausdrucks 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 Trennzeichenfolge der Felder modelliert, „\s*,\s*“. Mit der Methode split der Klasse Pattern können wir die Felder in ein Array extrahieren:
public String[] split(CharSequence input)
Die Zeichenkette input wird in Felder zerlegt, wobei diese durch ein Trennzeichen getrennt sind, das dem Muster des aktuellen Objekts Pattern entspricht. Um die Felder einer Zeile abzurufen, deren Feldtrennzeichen ein Komma ist, dem eine beliebige Anzahl von Leerzeichen vorangeht oder folgt, schreibt man:
// eine Zeile
String ligne="abc ,, def , ghi";
// ein Muster
Pattern modèle=Pattern.compile("\\s*,\\s*");
// Aufteilung einer Zeile in Felder
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.*;
// Verwaltung regulärer Ausdrücke
public class split1 {
public static void main(String[] args){
// eine Zeile
String ligne="abc ,, def , ghi";
// eine Vorlage
Pattern modèle=Pattern.compile("\\s*,\\s*");
// Aufteilung einer Zeile in Felder
String[] champs=modèle.split(ligne);
// Anzeige
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
// eine andere Vorgehensweise
champs=ligne.split("\\s*,\\s*");
// Anzeige
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//für
}//Hauptseite
}//Klasse
Die 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 häufig wie folgt aufgerufen:
$ pg -o1 v1 v2 ... -o2 v3 v4 …
wobei -oi eine Option und vi einen dieser Option zugeordneten Wert darstellt. Es soll eine Optionsklasse erstellt werden, mit der die Argumentkette -o1 v1 v2 ... -o2 v3 v4 … analysiert werden kann, um die folgenden Entitäten zu bilden:
optionsValides | einem Wörterbuch (Hashtable), dessen Schlüssel die gültigen Optionen oi 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 |
optionsInvalides | Hashtabelle, deren Schlüssel die ungü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 |
optionsSans | Zeichenkette (String), die die Liste der Werte vi angibt, die keiner Option zugeordnet sind |
erreur | Ganzzahl mit dem Wert 0, wenn die Argumentzeile keine Fehler enthält, andernfalls ein anderer Wert: 1: Es sind ungültige Aufrufparameter vorhanden 2: Es sind ungültige Optionen vorhanden 4: Es gibt Werte, die keiner Option zugeordnet sind Wenn mehrere Fehlerarten vorliegen, werden diese Werte addiert. |
Ein Optionsobjekt kann auf vier verschiedene Arten erstellt werden:
public options (String arguments, String optionsAcceptables)
arguments | die zu analysierende Argumentzeile -o1 v1 v2 ... -o2 v3 v4 … |
optionsAcceptables | die Liste der zulässigen Optionen oi |
Aufrufbeispiel: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");
Hier sind beide Argumente Zeichenketten. Es werden auch Fälle akzeptiert, in denen diese Zeichenketten in Wörter zerlegt und in ein Zeichenketten-Array gespeichert wurden. Dazu sind drei weitere Konstruktoren erforderlich:
public options (String[] arguments, String optionsAcceptables)
public options (String arguments, String[] optionsAcceptables)
public options (String[] arguments, String[] optionsAcceptables)
Die Klasse „options“ wird die folgende Schnittstelle (Accessoren) aufweisen:
gibt die Referenz des Arrays optionsValides zurück, das bei der Erstellung des Optionsobjekts angelegt wurde
gibt die Referenz auf das Array optionsInvalides zurück, das bei der Erstellung des Optionsobjekts angelegt wurde
gibt die Referenz der Zeichenkette „optionsSans“ zurück, die bei der Erstellung des Optionsobjekts gebildet wurde
gibt den Wert des Attributs „Fehler“ zurück, das bei der Erstellung des Optionsobjekts generiert wurde
gibt bei fehlendem Fehler die Werte der Attribute optionsValides, optionsInvalides, optionsSans aus, andernfalls die Fehlernummer.
Hier ist ein Beispielprogramm:
import java.io.*;
//Importoptionen;
public class test1{
public static void main (String[] arg){
// Öffnen des Eingabestroms
String ligne;
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
affiche(e);
System.exit(1);
}
// Auslesen der Argumente des Konstruktors 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));
}// Ende der while-Schleife
}//Ende von „main“
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//Ende der Klasse
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. Aufgabe 2
Es soll eine Klasse „stringtovector“ erstellt werden, mit der der Inhalt eines Objekts vom Typ String in ein Objekt vom Typ Vector übertragen werden kann. Diese Klasse soll von der Klasse Vector abgeleitet sein:
und hätte den folgenden Konstruktor:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// Erstellt ein Array mit den Feldern der Zeichenkette S
// Diese besteht aus Feldern, die durch das Trennzeichen getrennt sind
// Wenn das Trennzeichen null ist, bildet die Zeichenkette nur ein einziges Feld
// Es werden nur die Felder benötigt, deren Indizes im Array tChampsVoulus
// erwünscht sind. Die Indizes beginnen bei 1
// Wenn tChampsvoulus = null oder die Größe null ist, werden alle Felder berücksichtigt
// Wenn „strict“=true ist, müssen alle gewünschten Felder vorhanden sein
Die Klasse hätte das folgende private Attribut:
Dieses Attribut wird vom vorherigen Konstruktor mit den folgenden Werten gesetzt:
0: Die Erstellung verlief erfolgreich
4: Einige der angeforderten Felder fehlen, obwohl strict=true ist
Die Klasse verfügt außerdem über zwei Methoden:
die den Wert des privaten Attributs erreur zurückgibt.
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:
- Um die Zeichenkette S in Felder aufzuteilen, verwenden Sie die Methode split der Klasse String.
- Die Felder von S in ein Wörterbuch D einfügen, das nach der Feldnummer indiziert ist
- Rufen Sie aus dem Dictionary D nur die Felder ab, deren Schlüssel (Index) im Array tChampsVoulus enthalten ist.
4.12.3. Aufgabe 3
Man möchte der Klasse **stringtovector** den folgenden Konstruktor hinzufügen:
public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
// Erstellt einen Vektor mit den Feldern der Zeichenkette S
// Diese besteht aus Feldern, die durch das Trennzeichen getrennt sind
// Wenn „separator“ = null ist, bildet die Zeichenkette nur ein einziges Feld
// Es werden nur die Felder benötigt, deren Indizes in sChampsVoulus enthalten sind
// Die Indizes beginnen bei 1
// Wenn sChampsvoulus = null oder „“, werden alle Felder übernommen
// Wenn „strict“=true ist, müssen alle gewünschten Felder vorhanden sein
Die Liste der gewünschten Felder liegt also in einer Zeichenkette (String) statt in einem Array von Ganzzahlen (int[]). Dem privaten Attribut erreur der Klasse kann ein neuer Wert zugewiesen werden:
2: Die Zeichenfolge der Indizes der gewünschten Felder ist falsch
Hier 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:
- Man muss auf den Fall des vorherigen Konstruktors zurückgreifen, indem man die Felder der Zeichenkette sChampsVoulus in ein Array von Ganzzahlen überträgt. Dazu muss man sChampsVoulus mit einem Objekt StringTokenizer in Felder zerlegen, wobei das Attribut countTokens die Anzahl der erhaltenen Felder angibt. Anschließend kann man ein Array von Ganzzahlen mit der richtigen Größe erstellen und es mit den erhaltenen Feldern füllen.
- Um festzustellen, ob ein Feld eine Ganzzahl ist, verwenden Sie die Methode Integer.parseInt, um das Feld in eine Ganzzahl umzuwandeln, und behandeln Sie die Ausnahme, die generiert wird, wenn diese Konvertierung nicht möglich ist.
4.12.4. Übung 4
Es soll eine Klasse „filetovector“ erstellt werden, mit der der Inhalt einer Textdatei in ein Objekt vom Typ Vector übertragen werden kann. Diese Klasse würde von der Klasse Vector abgeleitet sein:
und hätte den folgenden Konstruktor:
// --------------------- Konstruktor
public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
// Erstellt einen Vektor mit den Zeilen der Textdatei nomFichier
// Die Zeilen bestehen aus Feldern, die durch das Trennzeichen getrennt sind
// Wenn das Trennzeichen null ist, besteht die Zeile nur aus einem einzigen Feld
// Es werden nur die Felder benötigt, deren Indizes in tChampsVoulus enthalten sind
// Die Indizes beginnen bei 1
// Wenn tChampsvoulus = null oder leer ist, werden alle Felder übernommen
// Wenn „strict“=wahr ist, müssen alle gewünschten Felder vorhanden sein
// Ist dies nicht der Fall, wird die Zeile nicht gespeichert und ihr Index
// wird in den Vektor lignesErronees
// Leerzeilen werden ignoriert
// ebenso wie Zeilen, die mit tagCommentaire beginnen, sofern tagCommentaire != null
Die Klasse hätte die folgenden privaten Attribute:
Das Attribut erreur wird vom vorherigen Konstruktor mit den folgenden Werten gesetzt:
0: Die Erstellung verlief erfolgreich
1: Die zu verarbeitende Datei konnte nicht geöffnet werden
4: Einige der angeforderten Felder fehlen, obwohl „strict=true“ gesetzt ist
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 Zeichenketten sind. Eine Zeile ist fehlerhaft, wenn sie die angeforderten Felder nicht bereitstellen kann, obwohl „strict=true“ gesetzt ist.
Die Klasse verfügt außerdem über zwei Methoden:
das den Wert des privaten Attributs erreur zurückgibt.
das 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 erstellten Vektors und li die Nummern der fehlerhaften Zeilen sind.
Hier ein Testbeispiel:
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());
}
}
Die 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,# Kommentar) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# Kommentar) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Einige Tipps
-
Die Textdatei wird zeilenweise verarbeitet. Die Zeile wird mithilfe der zuvor behandelten Klasse
**stringtovector** in Felder zerlegt. -
Die Elemente des aus der Textdatei gebildeten Vektors sind somit Objekte vom Typ „stringtovector“.
-
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 eventueller fehlerhafter Zeilen anzuzeigen.
4.12.5. Übung 5
Man möchte der Klasse „filetovector“ den folgenden Konstruktor hinzufügen:
public filetovector(String nomFichier, String separateur, String sChampsVoulus,
boolean strict, String tagCommentaire){
// erstellt einen Vektor mit den Zeilen aus der Textdatei nomFichier
// Die Zeilen bestehen aus Feldern, die durch das Trennzeichen getrennt sind
// Wenn das Trennzeichen null ist, besteht die Zeile nur aus einem einzigen Feld
// Es werden nur die Felder benötigt, deren Indizes in tChampsVoulus enthalten sind
// Die Indizes beginnen bei 1
// Wenn sChampsvoulus = null oder leer ist, werden alle Felder übernommen
// Wenn „strict“=wahr ist, müssen alle gewünschten Felder vorhanden sein
// Ist dies nicht der Fall, wird die Zeile nicht gespeichert und ihr Index
// wird in den Vektor lignesErronees
// Leerzeilen werden ignoriert
// ebenso wie Zeilen, die mit tagCommentaire beginnen, sofern tagCommentaire != null
Die Liste der Indizes der gewünschten Felder liegt nun in einer Zeichenkette (String) vor, anstatt in einem Array von Ganzzahlen.
Das private Attribut erreur kann einen zusätzlichen Wert annehmen:
2: Die Zeichenkette mit den Indizes der gewünschten Felder ist fehlerhaft
Hier ein Beispiel für einen Test:
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());
}
}
Die 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,# Kommentar) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# Kommentar) (0,azerty,1,cvf,fff,qqqq) (0,s)]
Einige Tipps
- Wir wandeln die Zeichenkette sChampsVoulus in ein Array von Ganzzahlen tChampVoulus um, um zum Fall des vorherigen Konstruktors zurückzukehren.