Skip to content

4. الفئات الشائعة الاستخدام في Java

في هذا الفصل، نقدم عددًا من فئات Java الشائعة الاستخدام. تحتوي هذه الفئات على العديد من السمات والطرق والمُنشِئات. في كل حالة، نقدم جزءًا صغيرًا فقط من الفئات. تتوفر تفاصيل حول هذه الفئات في تعليمات Java، التي نقدمها الآن.

4.1. الوثائق

إذا كنت قد قمت بتثبيت Sun JDK في المجلد <jdk>، فإن الوثائق متوفرة في المجلد <jdk>\docs:

Image

في بعض الأحيان يكون لديك JDK ولكن لا توجد وثائق. يمكن العثور عليها على موقع Sun على الويب على http://www.sun.com. في مجلد docs، ستجد ملف index.html، والذي يعمل كنقطة انطلاق لمساعدة JDK:

Image

Image

يوفر الرابط "API & Language" أعلاه إمكانية الوصول إلى فئات Java. ويعد الرابط "Demos/Tutorials" مفيدًا بشكل خاص للعثور على أمثلة لبرامج Java. دعونا نتبع الرابط "API & Language":

Image

دعونا نتبع رابط Java 2 Platform API:

Image

هذه الصفحة هي نقطة البداية الحقيقية لوثائق الفئات. يمكنك إنشاء اختصار لها للوصول السريع. عنوان URL هو <jdk>\docs\api\index.html. وهي تحتوي على روابط لمئات من فئات Java في JDK. عندما تكون في البداية، فإن التحدي الرئيسي هو معرفة ما تفعله هذه الفئات المختلفة. في البداية، لا يكون هذا المورد مفيدًا إلا إذا كنت تعرف اسم الفئة التي تريد معلومات عنها. يمكنك أيضًا استخدام أسماء الفئات كدليل، حيث إنها تشير عادةً إلى الغرض من الفئة.

لنأخذ مثالاً ونبحث عن معلومات حول فئة Vector، التي تنفذ مصفوفة ديناميكية. ما عليك سوى البحث في قائمة الفئات في الجزء الأيسر عن رابط فئة Vector:

Image

وانقر على الرابط لعرض تعريف الفئة:

Image

هناك ستجد

  • التسلسل الهرمي الذي توجد فيه الفئة، وهو في هذه الحالة java.util.Vector
  • قائمة الحقول (السمات) للفئة
  • قائمة المنشئات
  • قائمة الطرق

في الأقسام التالية، نقدم فئات متنوعة. ونشجع القارئ على التحقق بشكل منهجي من التعريف الكامل للفئات المستخدمة.

4.2. فئات الاختبار

تستخدم الأمثلة التالية أحيانًا فئتي Person و Teacher. نقدم تعريفاتهما هنا.

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;
  }
}

فئة Teacher مشتقة من فئة Person ويتم تعريفها على النحو التالي:

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+")";    
  }
}

سنستخدم أيضًا فئة student مشتقة من فئة person ومُعرَّفة على النحو التالي:


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. فئة String

تمثل فئة String سلاسل الأحرف. لنفترض أن *name* متغير سلسلة أحرف:

*<bdi dir="ltr" class="odt-ltr-term">String name</bdi>;*

name هو مرجع إلى كائن لم يتم تهيئته بعد. يمكن تهيئته بطريقتين:

**<bdi dir="ltr" class="odt-ltr-term">name</bdi> = &quot;<bdi dir="ltr" class="odt-ltr-term">horse</bdi>&quot;** أو **<bdi dir="ltr" class="odt-ltr-term">name</bdi> = <bdi dir="ltr" class="odt-ltr-term">new String</bdi>(&quot;<bdi dir="ltr" class="odt-ltr-term">horse</bdi>&quot;)**

كلا الطريقتين متكافئتان. إذا كتبنا لاحقًا name=&quot;fish&quot;، فإن name تشير عندئذٍ إلى كائن جديد. ويُفقد الكائن القديم String(&quot;horse&quot;)، ويتم استرداد الذاكرة التي كان يشغلها.

تحتوي فئة String على العديد من السمات والطرق. فيما يلي بعض منها:

public char charAt(int i)
تُرجع الحرف الموجود في المؤشر i في السلسلة، حيث يكون المؤشر 0 هو الحرف الأول. وبالتالي، فإن `String("horse").charAt(3)` يساوي 'h'
public int compareTo(string2)
تقوم string1.compareTo(string2) بمقارنة string1 بـ string2 وتُرجع 0 إذا كانت string1 = string2، و1 إذا كانت string1 > string2، و-1 إذا كانت string1 < string2
public boolean equals(Object anObject)
تُرجع string1.equals(string2) القيمة true إذا كانت string1 = string2، و false في الحالات الأخرى
public String toLowerCase()
string1.toLowerCase() يحول string1 إلى أحرف صغيرة
public String toUpperCase()
string1.toUpperCase() يحول string1 إلى أحرف كبيرة
public String trim()
string1.trim() يزيل المسافات في بداية ونهاية string1
public String substring(int beginIndex, int endIndex)
String("chapeau").subString(2,4) يعرض السلسلة "ape"
public char[] toCharArray()
يحول أحرف السلسلة إلى مصفوفة أحرف
int length()
عدد الأحرف في السلسلة
int indexOf(String string2)
يعيد أول ظهور لـ string2 في السلسلة الحالية، أو -1 إذا لم تكن string2 موجودة
int indexOf(String string2, int startIndex)
تُرجع أول ظهور لـ string2 في السلسلة الحالية، أو -1 إذا لم يتم العثور على string2. يبدأ البحث من الحرف الموجود في الموضع startIndex.
int lastIndexOf(String string2)
تُرجع آخر موضع لـ string2 في السلسلة الحالية، أو -1 إذا لم تكن string2 موجودة
boolean startsWith(String string2)
تُرجع true إذا كانت السلسلة الحالية تبدأ بـ string2
boolean endsWith(String string2)
تُرجع true إذا كانت السلسلة الحالية تنتهي بـ string2
boolean matches(String regex)
تُرجع القيمة true إذا كانت السلسلة الحالية تتطابق مع التعبير العادي regex.
String[] split(String regex)
تتكون السلسلة الحالية من حقول مفصولة بسلسلة من الأحرف التي تتطابق مع التعبير العادي regex. تسترد طريقة split الحقول في صفيف.
String replace(char oldChar, char newChar)
يستبدل الحرف oldChar بالحرف newChar في السلسلة الحالية.

فيما يلي برنامج نموذجي:

// 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

والنتائج التي تم الحصول عليها:

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. فئة Vector

المتجه هو مصفوفة ديناميكية تتكون عناصرها من مراجع كائنات. وبالتالي فهو مصفوفة من الكائنات التي يمكن أن يتغير حجمها بمرور الوقت، وهو ما لا يمكن تحقيقه مع المصفوفات الثابتة التي تعرفنا عليها حتى الآن. فيما يلي بعض الحقول أو المنشئات أو الطرق الخاصة بهذه الفئة:

public Vector()
ينشئ متجهًا فارغًا
public final int size()
عدد العناصر في المتجه
public final void addElement(Object obj)
يضيف الكائن المشار إليه بواسطة obj إلى المتجه
public final Object elementAt(int index)
إشارة إلى الكائن الموجود في الفهرس في المصفوفة - تبدأ الفهارس من 0
public final Enumeration elements()
مجموعة العناصر في المصفوفة كعدد
public final Object firstElement()
إشارة إلى العنصر الأول في المصفوفة
public final Object lastElement()
إشارة إلى العنصر الأخير في المتجه
public final boolean isEmpty()
تُرجع القيمة true إذا كان المصفوف فارغًا
public final void removeElementAt(int index)
يزيل العنصر الموجود في الفهرس
public final void removeAllElements()
تقوم بمسح جميع العناصر من المصفوفة
public final String toString()
تُرجع سلسلة تمثل المصفوفة

فيما يلي برنامج اختباري:


// 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

دعونا نقوم بتجميع هذا البرنامج:

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

دعونا نقوم بتشغيل ملف test1.class:

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)

من الآن فصاعدًا، لن نكرر عملية تجميع وتشغيل برامج الاختبار. ما عليك سوى تكرار ما تم فعله أعلاه.

4.5. فئة ArrayList

تشبه فئة ArrayList فئة Vector. ولا تختلف عنها بشكل أساسي إلا عند استخدامها في وقت واحد من قبل عدة خيوط. وتختلف طرق تزامن الخيوط المستخدمة للوصول إلى Vector أو ArrayList. وبخلاف هذه الحالة، يمكن استخدام أي منهما بشكل متبادل. وفيما يلي بعض الحقول أو منشئات أو الطرق الخاصة بهذه الفئة:

ArrayList()
ينشئ مصفوفة فارغة
int size()
عدد العناصر في المصفوفة
void add(Object obj)
يضيف الكائن المشار إليه بواسطة obj إلى المصفوفة
void add(int index, Object obj)
يضيف الكائن المشار إليه بواسطة obj إلى المصفوفة في الموضع index
Object get(int index)
إشارة إلى الكائن الموجود في الموضع index في المصفوفة — تبدأ الفهرسة من 0
boolean isEmpty()
تُرجع true إذا كان المصفوف فارغًا
void remove(int index)
تزيل العنصر الموجود في الفهرس
void clear()
تقوم بمسح جميع عناصر المصفوفة
Object[] toArray()
يحول المصفوفة الديناميكية إلى مصفوفة قياسية
String toString()
تُرجع سلسلة تمثل المصفوفة

فيما يلي برنامج اختباري:

// 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

النتائج التي تم الحصول عليها هي نفسها كما في السابق.

4.6. فئة المصفوفات

تتيح فئة java.util.Arrays الوصول إلى طرق ثابتة تسمح بإجراء عمليات متنوعة على المصفوفات، ولا سيما فرز العناصر والبحث عنها. وفيما يلي بعض هذه الطرق:

static void sort(array)
تقوم بفرز المصفوفة باستخدام الترتيب الضمني لنوع بيانات المصفوفة، سواء كانت أرقامًا أو سلاسل نصية.
static void sort(Object[] array, Comparator C)
تقوم بفرز المصفوفة باستخدام دالة المقارنة C لمقارنة العناصر
static int binarySearch(array, element)
تُرجع موضع العنصر في المصفوفة، أو قيمة <0 في حالة عدم وجوده. يجب فرز المصفوفة مسبقًا.
static int binarySearch(Object[] array, Object element, Comparator C)
مثل ما سبق، ولكنها تستخدم دالة المقارنة C لمقارنة عنصرين في المصفوفة.

إليك المثال الأول:

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

دعونا نفحص هذا البرنامج. تقوم الدالة الرئيسية بإنشاء كائن sort2. ويكون منشئ فئة sort2 كما يلي:

   // 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

المصفوفة المراد فرزها هي مصفوفة من كائنات Person. تم تعريف فئة Person على أنها خاصة داخل فئة sort2. لا تعرف الطريقة الثابتة sort الخاصة بفئة Arrays كيفية فرز مصفوفة من كائنات Person، لذا نحن مضطرون هنا لاستخدام النموذج void sort(Object[] obj, Comparator C). Comparator هي واجهة تحدد طريقة واحدة فقط:

    int compare(Object o1, Object o2)

والتي يجب أن ترجع 0 إذا كان o1=o2، -1: إذا كان o1 < o2، +1: إذا كان o1 > o2. في النموذج الأولي void sort(Object[] obj, Comparator C يجب أن تكون الحجة الثانية C كائنًا ينفذ واجهة Comparator. في منشئ sort2، اخترنا الكائن الحالي this:

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

وهذا يتطلب منا القيام بأمرين:

  1. الإشارة إلى أن فئة sort2 تنفذ واجهة Comparator
public class sort2 implements Comparator{
  1. كتابة دالة المقارنة في فئة sort2.

وهذا كما يلي:

   // 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

لمقارنة كائنين من نوع Person، نستخدم العمر هنا (كان بإمكاننا استخدام الاسم).

فيما يلي نتائج التنفيذ:

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

كان بإمكاننا اتباع نهج مختلف لتنفيذ واجهة Comparator:

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

أصبحت عبارة الفرز كما يلي:

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

يجب أن تكون المعلمة الثانية لطريقة compare كائنًا يُنفِّذ واجهة Comparator. هنا، نقوم بإنشاء مثل هذا الكائن باستخدام new java.util.Comparator()، ويحدد النص الذي يلي {…} الفئة التي يتم إنشاء الكائن منها. وتُسمَّى هذه الفئة «فئة مجهولة» لأنها لا تحمل اسمًا. في هذه الفئة المجهولة، التي يجب أن تنفذ واجهة Comparator، نحدد طريقة compare لتلك الواجهة. هذه الطريقة تستدعي ببساطة طريقة compare1 لفئة sort2. ثم نعود إلى الحالة السابقة.

لم تعد فئة sort2 تنفذ واجهة Comparator. لذلك، يصبح إعلانها كما يلي:

public class sort2 {

الآن نختبر طريقة binarySearch لفئة Arrays باستخدام المثال التالي:

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

هنا، اتبعنا نهجًا مختلفًا قليلاً عن الأمثلة السابقة. تم إنشاء كائني Comparator المطلوبين من قبل طريقتي sort و binarySearch وتعيينهما للمتغيرين comparator1 و comparator2.

     // 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
      ;          

يتم إجراء بحث ثنائي على مصفوفة friends مرتين في منشئ sort4:

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

تستقبل طريقة البحث جميع المعلمات التي تحتاجها لاستدعاء طريقة binarySearch:

    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

تعمل طريقة binarySearch مع المقارن comparator2، الذي بدوره يستدعي طريقة compare2 من فئة sort4. تُرجع الطريقة موضع الاسم الذي تم البحث عنه في المصفوفة إذا كان موجودًا، أو رقمًا <0 في حالة عدم وجوده. تُستخدم طريقة compare2 لمقارنة كائن Person باسم من نوع String.

   // 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

على عكس طريقة sort، لا تتطلب طريقة binarySearch كائنين من نوع Person، بل كائنًا من نوع Person وكائنًا من نوع String بهذا الترتيب. المعلمة الأولى هي عنصر من مصفوفة friends، أما الثانية فهي اسم الشخص المطلوب البحث عنه.

4.7. فئة Enumeration

Enumeration هي واجهة، وليست فئة. وتحتوي على الطرق التالية:

public abstract boolean hasMoreElements()
تُرجع القيمة true إذا كان التعداد لا يزال يحتوي على عناصر
public abstract Object nextElement()
تُرجع مرجعًا إلى العنصر التالي في التعداد

كيف تستخدم التعداد؟ بشكل عام هكذا:

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

فيما يلي مثال:


// 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

تم الحصول على النتائج التالية:

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. فئة HashTable

تسمح لك فئة HashTable بتنفيذ قاموس. يمكن النظر إلى القاموس على أنه مصفوفة من عمودين:

المفتاح
القيمة
المفتاح 1
القيمة1
المفتاح 2
القيمة 2
..
...

المفاتيح فريدة، أي لا يمكن أن يكون هناك مفتاحان متطابقان. فيما يلي الطرق والخصائص الرئيسية لفئة Hashtable:

public Hashtable()
منشئ - ينشئ قاموسًا فارغًا
public int size()
عدد العناصر في القاموس — حيث العنصر هو زوج (مفتاح، قيمة)
public Object put(Object key, Object value)
يضيف الزوج (المفتاح، القيمة) إلى القاموس
public Object get(Object key)
تسترد الكائن المرتبط بالمفتاح key أو القيمة null إذا كان المفتاح key غير موجود
public boolean containsKey(Object key)
true إذا كان المفتاح موجودًا في القاموس
public boolean contains(Object value)
true إذا كانت القيمة value موجودة في القاموس
public Enumeration keys()
تُرجع مفاتيح القاموس كسلسلة
public Object remove(Object key)
يزيل الزوج (key, value) حيث key=key
public String toString()
يحدد القاموس

إليك مثال:


// 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

النتائج هي كما يلي:

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. ملفات نصية

4.9.1. الكتابة

للكتابة في ملف، تحتاج إلى دفق كتابة. يمكنك استخدام فئة FileWriter لهذا الغرض. تُستخدم المنشئات التالية بشكل شائع:

FileWriter(String fileName)
ينشئ ملفًا باسم fileName — يمكنك بعد ذلك الكتابة فيه — ويتم استبدال أي ملف موجود يحمل نفس الاسم
FileWriter(String fileName,
boolean append)
مثل ما سبق — يمكن استخدام أي ملف موجود يحمل نفس الاسم عن طريق فتحه في وضع الإضافة (append=true)

توفر فئة FileWriter عددًا من الطرق للكتابة إلى ملف، وهي طرق موروثة من فئة Writer. للكتابة إلى ملف نصي، يُفضل استخدام فئة PrintWriter، التي تكون منشئاتها الشائعة الاستخدام كما يلي:

PrintWriter(Writer out)
الحجة من نوع Writer، أي تيار كتابة (إلى ملف، عبر الشبكة، إلخ)
PrintWriter(Writer out, boolean autoflush)
كما هو مذكور أعلاه. تتحكم الحجة الثانية في التخزين المؤقت للسطور. عند تعيينها على false (القيمة الافتراضية)، تمر السطور المكتوبة إلى الملف عبر مخزن مؤقت في الذاكرة. وعندما يمتلئ المخزن المؤقت، يتم كتابتها إلى الملف. وهذا يحسن الوصول إلى القرص. ومع ذلك، قد يكون هذا السلوك غير مرغوب فيه أحيانًا، خاصة عند الكتابة عبر الشبكة.

فيما يلي الطرق المفيدة لفئة PrintWriter:

void print(Type T)
تكتب البيانات T (String، int، ….)
void println(Type T)
مثل ما سبق، مع إنهاء السطر بحرف جديد
void flush()
تفرغ المخزن المؤقت إذا لم يكن في وضع التفريغ التلقائي
void close()
يغلق دفق الكتابة

فيما يلي برنامج يكتب بضعة أسطر في ملف نصي:

// 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

الملف الناتج الذي أنشأه البرنامج هو كما يلي:

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

4.9.2. قراءة

لقراءة محتويات ملف ما، تحتاج إلى دفق قراءة مرتبط بالملف. يمكنك استخدام فئة FileReader والمُنشئ التالي لهذا الغرض:

FileReader(String filename)
يفتح تيار قراءة من الملف المحدد. يرمي استثناءً إذا فشلت العملية.

تحتوي فئة FileReader على عدد من الطرق لقراءة الملفات، وهي طرق موروثة من فئة Reader. لقراءة أسطر النص من ملف نصي، يفضل استخدام فئة BufferedReader مع المنشئ التالي:

BufferedReader(Reader in)
يفتح دفق قراءة مؤقت من دفق إدخال in. يمكن أن يأتي هذا الدفق من نوع Reader من لوحة المفاتيح أو ملف أو الشبكة، إلخ.

الطرق المفيدة لفئة BufferedReader هي كما يلي:

int read()
يقرأ حرفًا
String readLine()
تقرأ سطرًا من النص
int read(char[] buffer, int offset, int size)
يقرأ عدد أحرف من الملف ويضعها في مصفوفة المخزن المؤقت بدءًا من الموضع offset.
void close()
يغلق دفق القراءة

فيما يلي برنامج يقرأ محتويات الملف الذي تم إنشاؤه سابقًا:

// 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

يؤدي تشغيل البرنامج إلى النتائج التالية:

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

4.9.3. حفظ كائن شخص

نطبق ما رأيناه للتو لتزويد فئة Person بطريقة تسمح لنا بحفظ سمات الشخص في ملف. نضيف الطريقة saveAttributes إلى تعريف فئة Person:


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

قبل تعريف فئة Person، لا تنسَ استيراد حزمة java.io:

import java.io.*;

تأخذ طريقة saveAttributes معلمة واحدة: دفق PrintWriter الذي يجب أن تكتب إليه. قد يبدو برنامج الاختبار كما يلي:

// 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

دعونا نقوم بتجميع وتشغيل هذا البرنامج:

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. الملفات الثنائية

4.10.1. فئة RandomAccessFile

تسمح لك فئة RandomAccessFile بإدارة الملفات الثنائية، خاصة تلك ذات البنية الثابتة كما هو الحال في C/C++. فيما يلي بعض الطرق والمُنشِئات المفيدة:

RandomAccessFile(String filename, String mode)
منشئ - يفتح الملف المحدد في الوضع المحدد. يمكن أن يكون الوضع أحد الخيارات التالية:
r: فتح للقراءة
rw: فتح للقراءة والكتابة
void writeTTT(TTT value)
يكتب القيمة إلى الملف. يمثل TTT نوع القيمة. يتم كتابة تمثيل الذاكرة للقيمة كما هو إلى الملف. وبالتالي، هناك writeBoolean و writeByte و writeInt و writeDouble و writeLong و writeFloat، إلخ. لكتابة سلسلة، استخدم writeBytes(String string).
TTT readTTT()
يقرأ ويعيد قيمة من النوع TTT. ومن الأمثلة على ذلك readBoolean و readByte و readInt و readDouble و readLong و readFloat، إلخ. تقرأ طريقة read() بايتًا واحدًا.
long length()
حجم الملف بالبايت
long getFilePointer()
الموضع الحالي لمؤشر الملف
void seek(long pos)
يضبط مؤشر الملف على البايت pos

4.10.2. فئة Article

ستستخدم جميع الأمثلة التالية فئة article التالية:

     // 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

فئة Item في Java أعلاه تعادل البنية التالية في لغة C

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

بهذه الطريقة، سنحدد طول الكود بـ 4 أحرف وطول الاسم بـ 20 حرفًا.

4.10.3. تسجيل

يكتب البرنامج التالي سجلاً في ملف باسم "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

يتيح لنا البرنامج التالي التحقق من نجاح التنفيذ.

4.10.4. قراءة سجل

// 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

نتائج التنفيذ هي كما يلي:

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

لقد نجحنا في استرداد السجل الذي كتبه برنامج الكتابة.

4.10.5. تحويل النص إلى ثنائي

البرنامج التالي هو امتداد لبرنامج كتابة السجلات. نكتب الآن سجلات متعددة إلى ملف ثنائي باسم data.bin. يتم أخذ البيانات من ملف 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

يتيح لك البرنامج التالي التحقق من أن هذا البرنامج يعمل بشكل صحيح.

4.10.6. تحويل ثنائي إلى نص

يقرأ البرنامج التالي محتويات الملف الثنائي data.bin الذي تم إنشاؤه سابقًا ويكتب محتوياته في الملف النصي data.text. إذا سارت الأمور على ما يرام، يجب أن يكون الملف data.text مطابقًا للملف الأصلي data.txt.

// 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

فيما يلي مثال على التنفيذ:

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. الوصول المباشر إلى السجلات

يوضح هذا البرنامج الأخير القدرة على الوصول المباشر إلى السجلات في ملف ثنائي. يعرض السجل من ملف data.bin الذي يتم تمرير رقمه كمعلمة، مع كون السجل الأول يحمل الرقم 1.

// 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

فيما يلي بعض أمثلة التنفيذ:

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. استخدام التعبيرات العادية

4.11.1. حزمة java.util.regex في Java

تسمح حزمة java.util.regex باستخدام التعبيرات العادية. تتيح لك هذه التعبيرات التحقق من صحة تنسيق سلسلة. على سبيل المثال، يمكنك التحقق من أن سلسلة تمثل تاريخًا بتنسيق dd/mm/yy. للقيام بذلك، تستخدم نمطًا وتقارن السلسلة بهذا النمط. في هذا المثال، يجب أن تكون d و m و y أرقامًا. وبالتالي، فإن النمط الخاص بتنسيق التاريخ الصحيح هو "\d\d/\d\d/\d\d"، حيث يمثل الرمز \d رقمًا. الرموز التي يمكن استخدامها في النمط هي كما يلي (وثائق Microsoft):

الحرف
الوصف
\
يشير إلى الحرف التالي كحرف خاص أو حرفي. على سبيل المثال، "n" يقابل الحرف "n". "\n" يقابل حرف السطر الجديد. التسلسل "\\" يقابل "\"، بينما "\(" يقابل "(".
^
يطابق بداية الإدخال.
$
يتطابق مع نهاية الإدخال.
*
يتطابق مع الحرف السابق صفر أو أكثر من مرة. وبالتالي، فإن "zo*" يتطابق مع "z" أو "zoo".
+
يتطابق مع الحرف السابق مرة واحدة أو أكثر. وبالتالي، فإن "zo+" يتطابق مع "zoo"، ولكنه لا يتطابق مع "z".
?
يتطابق مع الحرف السابق صفر أو مرة واحدة. على سبيل المثال، "a?ve?" يتطابق مع "ve" في "lever".
.
يتطابق مع أي حرف واحد، باستثناء حرف السطر الجديد.
(النمط)
يبحث عن النمط ويخزن المطابقة. يمكن استرداد السلسلة الفرعية المطابقة من مجموعة Matches الناتجة باستخدام Item [0]...[n]. للعثور على المطابقات التي تحتوي على أحرف داخل أقواس ( )، استخدم "\(" أو "\)".
x|y
يطابق إما x أو y. على سبيل المثال، "z|foot" يطابق "z" أو "foot". "(z|f)oo" يطابق "zoo" أو "foo".
{n}
n هو عدد صحيح غير سالب. يطابق n مرة بالضبط من ظهور الحرف. على سبيل المثال، "o{2}" لا يطابق "o" في "Bob"، ولكنه يطابق أول حرفين "o" في "fooooot".
{n,}
n هو عدد صحيح غير سالب. يطابق ما لا يقل عن n تكرارًا للحرف. على سبيل المثال، "o{2,}" لا يطابق "o" في "Bob"، ولكنه يطابق جميع أحرف "o" في "fooooot". "o{1,}" يعادل "o+" و "o{0,}" يعادل "o*".
{n,m}
m و n عددان صحيحان غير سالبين. يطابق ما لا يقل عن n وما لا يزيد عن m تكرارات للحرف. على سبيل المثال، يطابق "o{1,3}" الأحرف الثلاثة الأولى من نوع "o" في الكلمة "foooooot"، أما "o{0,1}" فيعادل "o?".
[xyz]
مجموعة أحرف. يطابق أيًا من الأحرف المحددة. على سبيل المثال، يطابق "[abc]" الحرف "a" في كلمة "plat".
[^xyz]
مجموعة الأحرف السلبية. تتطابق مع أي حرف غير مدرج. على سبيل المثال، "[^abc]" تتطابق مع الحرف "p" في كلمة "plat".
[a-z]
نطاق الأحرف. يطابق أي حرف في النطاق المحدد. على سبيل المثال، يطابق "[a-z]" أي حرف أبجدي صغير بين "a" و "z".
[^m-z]
نطاق الأحرف السلبية. يطابق أي حرف غير موجود في النطاق المحدد. على سبيل المثال، يطابق "[^m-z]" أي حرف غير موجود بين "m" و "z".
\b
يتطابق مع حدود الكلمة، أي الموضع بين الكلمة والمسافة. على سبيل المثال، يتطابق "er\b" مع "er" في "lever"، ولكنه لا يتطابق مع "er" في "verb".
\B
يتطابق مع حد لا يمثل كلمة. يتطابق "en*t\B" مع "ent" في "bien entendu".
\d
يتطابق مع حرف يمثل رقمًا. يعادل [0-9].
\D
يتطابق مع حرف ليس رقمًا. يعادل [^0-9].
\f
يتطابق مع حرف فاصل الأسطر.
\n
يتطابق مع حرف السطر الجديد.
\r
مكافئ لحرف إرجاع الحامل.
\s
يتطابق مع أي مسافة بيضاء، بما في ذلك المسافة، وعلامة الجدولة، وفاصل الصفحة، وما إلى ذلك. يعادل "[ \f\n\r\t\v]".
\S
يتطابق مع أي حرف غير مسافة بيضاء. يعادل "[^ \f\n\r\t\v]".
\t
يتطابق مع حرف الجدولة.
\v
يتطابق مع حرف الجدولة الرأسية.
\w
يتطابق مع أي حرف يمثل كلمة ويشمل شرطة سفلية. يعادل "[A-Za-z0-9_]".
\W
يتطابق مع أي حرف لا يمثل كلمة. يعادل "[^A-Za-z0-9_]".
\num
يتطابق مع num، حيث num هو عدد صحيح موجب. يشير إلى التطابقات المخزنة. على سبيل المثال، يتطابق "(.)\1" مع حرفين متتاليين متطابقين.
\n
يتطابق مع n، حيث n هو قيمة هروب ثمانية. يجب أن تتكون قيم الهروب الثمانية من 1 أو 2 أو 3 أرقام. على سبيل المثال، يتطابق كل من "\11" و "\011" مع حرف الجدولة. "\0011" يعادل "\001" و "1". يجب ألا تتجاوز قيم الهروب الثمانية 256. إذا تجاوزت ذلك، يتم أخذ أول رقمين فقط في الاعتبار في التعبير. يسمح باستخدام رموز ASCII في التعبيرات العادية.
\xn
يتوافق مع n، حيث n هي قيمة هروب سداسية عشرية. يجب أن تتكون قيم الهروب السداسية العشرية من رقمين بالضبط. على سبيل المثال، "\x41" يتوافق مع "A". "\x041" يعادل "\x04" و "1". يسمح باستخدام رموز ASCII في التعبيرات العادية.

قد يظهر عنصر في نمط مرة واحدة أو عدة مرات. دعونا نلقي نظرة على بعض الأمثلة التي تتضمن الرمز \d، الذي يمثل رقمًا واحدًا:

النمط
المعنى
\d
رقم
\d?
رقم واحد أو صفر
\d*
رقم واحد أو أكثر
\d+
رقم واحد أو أكثر
\d{2}
رقمان
\d{3,}
3 أرقام على الأقل
\d{5,7}
ما بين 5 و 7 أرقام

الآن دعونا نتخيل نموذجًا قادرًا على وصف التنسيق المتوقع لسلسلة:

السلسلة المستهدفة
النمط
تاريخ بتنسيق dd/mm/yy
\d{2}/\d{2}/\d{2}
وقت بتنسيق hh:mm:ss
\d{2}:\d{2}:\d{2}
عدد صحيح غير موقّع
\d+
سلسلة من المسافات، قد تكون فارغة
\s*
عدد صحيح غير موقّع قد يسبقه أو يتبعه مسافات
\s*\d+\s*
عدد صحيح قد يكون موقّعًا ويسبقه أو يتبعه مسافات
\s*[+|-]?\s*\d+\s*
عدد حقيقي غير موقّع قد يسبقه أو يتبعه مسافات
\s*\d+(.\d*)?\s*
عدد حقيقي قد يكون له إشارة ويسبقه أو يتبعه مسافات
\s*[+|]?\s*\d+(.\d*)?\s*
سلسلة تحتوي على كلمة "just"
\bjuste\b
  

يمكنك تحديد مكان البحث عن النمط في السلسلة:

النمط
المعنى
^النمط
يبدأ النمط السلسلة
النمط$
ينهي النمط السلسلة
^النمط$
يبدأ النمط السلسلة وينهيها
النمط
يتم البحث عن النمط في أي مكان في السلسلة، بدءًا من البداية.
سلسلة البحث
النمط
سلسلة تنتهي بعلامة تعجب
!$
سلسلة تنتهي بنقطة
\.$
سلسلة تبدأ بالتسلسل //
^//
سلسلة تتكون من كلمة واحدة، تليها أو تسبقها مسافات اختيارياً
^\s*\w+\s*$
سلسلة تتكون من كلمتين، يمكن أن تسبقها أو تتبعها مسافات
^\s*\w+\s*\w+\s*$
سلسلة تحتوي على كلمة secret
\bsecret\b

يمكن "استخراج" الأنماط الفرعية لنمط ما. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نمط معين، بل يمكننا أيضًا استخراج العناصر المطابقة للأنماط الفرعية للنمط التي تم وضعها بين قوسين من تلك السلسلة. على سبيل المثال، إذا كنا نقوم بتحليل سلسلة تحتوي على تاريخ بتنسيق dd/mm/yy ونريد أيضًا استخراج العناصر dd و mm و yy من هذا التاريخ، فسنستخدم النمط (\d\d)/(\d\d)/(\d\d).

4.11.2. التحقق مما إذا كانت سلسلة تتطابق مع نمط معين

تسمح لك فئة Pattern بالتحقق مما إذا كانت سلسلة تتطابق مع نمط معين. للقيام بذلك، استخدم الطريقة الثابتة

boolean Matches(String modèle, String chaine)

مع: pattern: النمط المراد التحقق منه، string: السلسلة المراد مقارنتها بالنمط. تكون النتيجة هي القيمة المنطقية true إذا كانت السلسلة تتطابق مع النمط، و false في حالة عدم التطابق.

فيما يلي مثال:

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

ونتيجة التنفيذ:

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

لاحظ أنه في النمط "^\s*\d+\s*$"، يجب مضاعفة الحرف \ بسبب تفسير Java الخاص لهذا الحرف. لذلك نكتب: String pattern1="^\\s*\\d+\\s*$";

4.11.3. البحث عن جميع عناصر السلسلة التي تتطابق مع نمط

لنأخذ النمط "\d+" والسلسلة " 123 456 789 " كمثال. يوجد النمط في ثلاثة أماكن مختلفة في السلسلة. تتيح لك فئتا Pattern و Matcher استرداد المرات المختلفة لظهور نمط ما في سلسلة. فئة Pattern هي الفئة التي تتعامل مع التعبيرات العادية. يجب "تجميع" التعبير العادي المستخدم أكثر من مرة. يؤدي ذلك إلى تسريع عمليات البحث عن الأنماط في السلاسل. تقوم طريقة التجميع الثابتة (static compile) بهذه المهمة:

public static Pattern compile(String regex)

تأخذ سلسلة النمط كمعلمة وتُرجع كائن Pattern. لمقارنة نمط كائن Pattern بسلسلة، نستخدم فئة Matcher. تسمح هذه الفئة بمقارنة نمط بسلسلة. من كائن Pattern، يمكن الحصول على كائن Matcher باستخدام طريقة matcher:

public Matcher matcher(CharSequence input)

input هي السلسلة التي سيتم مقارنتها بالنمط.

لذلك، لمقارنة النمط "\d+" بالسلسلة " 123 456 789 "، يمكنك إنشاء كائن Matcher كما يلي:

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

باستخدام كائن النتائج المذكور أعلاه، يمكننا استرداد المرات المختلفة لظهور النمط في السلسلة. للقيام بذلك، نستخدم الطرق التالية لفئة Matcher:

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

تبحث طريقة find في السلسلة التي تم استكشافها عن أول ظهور للنمط. سيؤدي استدعاء find للمرة الثانية إلى البحث عن الظهور التالي، وهكذا دواليك. ترجع الطريقة القيمة true إذا عثرت على النمط، وإلا ترجع القيمة false. يتم الحصول على الجزء من السلسلة المطابق لآخر ظهور عثرت عليه find باستخدام طريقة group، وموقعه باستخدام طريقة start. وبالتالي، استمرارًا للمثال السابق، إذا أردنا عرض جميع ظهورات النمط "\d+" في السلسلة " 123 456 789 "، فسنكتب:

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

تسمح لك طريقة reset بإعادة تعيين كائن Matcher إلى بداية السلسلة التي تتم مقارنتها بالنمط. وبهذه الطريقة، ستقوم طريقة find بالبحث عن أول ظهور للنمط مرة أخرى.

فيما يلي مثال كامل:

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

نتائج التنفيذ:

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. استخراج أجزاء من نمط

يمكن "استخراج" مجموعات فرعية من نمط ما. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نمط معين، بل يمكننا أيضًا استخراج العناصر المطابقة للمجموعات الفرعية للنمط التي تم وضعها بين قوسين من تلك السلسلة. على سبيل المثال، إذا كنا نقوم بتحليل سلسلة تحتوي على تاريخ بتنسيق dd/mm/yy ونريد أيضًا استخراج العناصر dd و mm و yy من هذا التاريخ، فسنستخدم النمط (\d\d)/(\d\d)/(\d\d).

دعونا ندرس المثال التالي:

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

يؤدي تشغيل هذا البرنامج إلى النتائج التالية:

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

توجد الميزة الجديدة في مقتطف الشفرة التالي:

    // 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+"]");
      }

يتم مقارنة السلسلة example4 بالنمط regex3 باستخدام طريقة find. ثم يتم العثور على تطابق للنمط regex3 في السلسلة example4. إذا كان النمط يتضمن مجموعات فرعية محاطة بأقواس، فيمكن الوصول إليها عبر طرق مختلفة لفئة Matcher:


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

تُرجع الطريقة groupCount عدد المجموعات الفرعية الموجودة في النمط، وتُرجع group(i) المجموعة الفرعية رقم i. وتوجد هذه المجموعة في السلسلة في الموضع المحدد بواسطة start(i). وبالتالي، في المثال:

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

سيؤدي الاستدعاء الأول لطريقة find إلى العثور على السلسلة 18:05:49 وإنشاء المجموعات الفرعية الثلاث المحددة بالأقواس في النمط تلقائيًا، وهي 18 و05 و49.

4.11.5. برنامج تعليمي

قد يمثل العثور على التعبير العادي الذي يسمح لنا بالتحقق مما إذا كانت سلسلة ما تتطابق مع نمط معين تحديًا حقيقيًا في بعض الأحيان. يتيح لك البرنامج التالي التدرب على ذلك. فهو يطلب نمطًا وسلسلة ثم يشير إلى ما إذا كانت السلسلة تتطابق مع النمط أم لا.

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

فيما يلي مثال على التنفيذ:

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. طريقة split في فئة Pattern

لنفترض أن لدينا سلسلة تتكون من حقول مفصولة بسلسلة فاصلة يتم التعبير عنها باستخدام تعبير عادي. على سبيل المثال، إذا كانت الحقول مفصولة بالحرف ، يسبقه أو يتبعه أي عدد من المسافات، فإن التعبير العادي الذي يمثل سلسلة فاصل الحقول سيكون "\s*,\s*". تسمح لنا طريقة split لفئة Pattern باسترداد الحقول في صفيف:


public String[] split(CharSequence input)

يتم تقسيم سلسلة الإدخال إلى حقول، يتم فصلها بفاصل يطابق نمط كائن Pattern الحالي. لاسترداد الحقول من سطر يكون فيه فاصل الحقول عبارة عن فاصلة يسبقها أو يتبعها أي عدد من المسافات، نكتب:

    // 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);

يمكنك تحقيق النتيجة نفسها باستخدام طريقة split في فئة String:


public String[] split(String regex)

فيما يلي برنامج اختباري:

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

نتائج التنفيذ:

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

4.12. تمارين

4.12.1. التمرين 1

في نظام Unix، غالبًا ما يتم استدعاء البرامج على النحو التالي:

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

حيث يمثل -oi خيارًا و vi قيمة مرتبطة بهذا الخيار. نريد إنشاء فئة خيارات تقوم بتحليل سلسلة الحجج -o1 v1 v2 ... -o2 v3 v4 … من أجل إنشاء الكيانات التالية:

ValidOptions
قاموس (Hashtable) تحتوي مفاتيحه على خيارات oi الصالحة. والقيمة المرتبطة بمفتاح oi هي متجه (Vector) تتكون عناصره من القيم v1 و v2 … المرتبطة بخيار -oi
invalidOptions
(Hashtable) الذي تكون مفاتيحه هي خيارات oi غير الصالحة. القيمة المرتبطة بالمفتاح oi هي متجه (Vector) عناصره هي القيم v1 v2 … المرتبطة بخيار -oi
optionsWithout
سلسلة (String) تسرد قيم vi غير المرتبطة بخيار
error
عدد صحيح يساوي 0 إذا لم تكن هناك أخطاء في قائمة الحجج، وإلا:
1: توجد معلمات استدعاء غير صالحة
2: توجد خيارات غير صالحة
4: توجد قيم غير مرتبطة بخيارات
إذا كانت هناك أنواع متعددة من الأخطاء، فإن هذه القيم تكون تراكمية.

يمكن إنشاء كائن الخيارات بأربع طرق مختلفة:

public options (String arguments, String optionsAcceptable)

arguments
حجج سطر الأوامر -o1 v1 v2 ... -o2 v3 v4 … المراد تحليلها
خيارات مقبولة
قائمة الخيارات المقبولة

مثال على الاستدعاء: options opt=new options("-u u1 u2 u3 -g g1 g2 -x","-u -g");

هنا، كلا الحجتين عبارة عن سلاسل. سنقبل الحالات التي تم فيها تقسيم هذه السلاسل إلى كلمات ووضعها في مصفوفة من السلاسل. وهذا يتطلب ثلاثة منشئات إضافية:

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

ستحتوي فئة الخيارات على الواجهة التالية (مُستردات):

public Hashtable getOptionsValides()

تُرجع مرجعًا إلى مصفوفة optionsValides التي تم إنشاؤها عند إنشاء كائن الخيارات

public Hashtable getOptionsInvalides()

تُرجع مرجعًا إلى مصفوفة invalidOptions التي تم إنشاؤها عند إنشاء كائن الخيارات

public String getOptionsSans()

تُرجع مرجعًا إلى سلسلة optionsWithout التي تم إنشاؤها عند إنشاء كائن options

public int getErreur()

تُرجع قيمة سمة error التي تم إنشاؤها عند إنشاء كائن options

public String toString()

في حالة عدم وجود أخطاء، تعرض قيم سمات optionsValides و optionsInvalides و optionsSans؛ وإلا، تعرض رقم الخطأ.

فيما يلي برنامج نموذجي:


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

بعض النتائج:

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. التمرين 2

نريد إنشاء فئة stringtovector تسمح لنا بنقل محتويات كائن String إلى كائن Vector. وستكون هذه الفئة مشتقة من فئة Vector:

class stringtovector extends Vector

وستحتوي على المنشئ التالي:


    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

ستحتوي الفئة على السمة الخاصة التالية:

        private int erreur;

يتم تعيين هذه السمة بواسطة المنشئ السابق بالقيم التالية:

0: تم الإنشاء بنجاح

4: بعض الحقول المطلوبة مفقودة على الرغم من أن strict=true

وستحتوي الفئة أيضًا على طريقتين:

    public int getErreur()

التي تُرجع قيمة السمة الخاصة error.

    public String identite(){

الذي يعرض قيمة الكائن في الصيغة (error, element 1, element 2, …) حيث العناصر i هي عناصر المتجه الذي تم إنشاؤه من السلسلة.

قد يبدو برنامج الاختبار كما يلي:


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());
  }
}

النتائج:

(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)

بعض النصائح:

  1. لتقسيم السلسلة S إلى حقول، استخدم طريقة split الخاصة بفئة String.
  2. ضع حقول S في قاموس D مفهرس برقم الحقل
  3. استرجع من القاموس D فقط الحقول التي توجد مفاتيحها (فهارسها) في المصفوفة tChampsVoulus.

4.12.3. التمرين 3

نريد إضافة المنشئ التالي إلى فئة stringtovector:


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

وبالتالي، فإن قائمة الحقول المطلوبة تكون في شكل سلسلة (String) بدلاً من مصفوفة من الأعداد الصحيحة (int[]). يمكن تعيين قيمة جديدة لخاصية الخطأ الخاصة بالفئة:

2: سلسلة مؤشرات الحقول المطلوبة غير صحيحة

فيما يلي برنامج نموذجي:


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());
  }
}

بعض النتائج:

(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)

بعض النصائح:

  1. تحتاج إلى العودة إلى حالة المنشئ السابق عن طريق نقل الحقول من السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة. للقيام بذلك، قم بتقسيم sChampsVoulus إلى حقول باستخدام كائن StringTokenizer، حيث ستعطي سمة countTokens عدد الحقول التي تم الحصول عليها. يمكنك بعد ذلك إنشاء مصفوفة من الأعداد الصحيحة بالحجم الصحيح وملؤها بالحقول التي تم الحصول عليها.
  2. لتحديد ما إذا كان الحقل عددًا صحيحًا، استخدم طريقة Integer.parseInt لتحويل الحقل إلى عدد صحيح والتعامل مع الاستثناء الذي سيتم طرحه إذا كان هذا التحويل غير ممكن.

4.12.4. التمرين 4

نريد إنشاء فئة filetovector تسمح لنا بنقل محتويات ملف نصي إلى كائن Vector. ستُشتق هذه الفئة من فئة Vector:

class filetovector extends Vector

وستحتوي على المنشئ التالي:


    // --------------------- 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

ستحتوي الفئة على السمات الخاصة التالية:

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

يتم تعيين السمة error بواسطة المنشئ السابق بالقيم التالية:

0: تمت عملية الإنشاء بنجاح

1: تعذر فتح الملف المراد معالجته

4: بعض الحقول المطلوبة مفقودة على الرغم من أن strict=true

8: حدث خطأ في الإدخال/الإخراج أثناء معالجة الملف

السمة lignesErronees هي متجه تتكون عناصره من أرقام الأسطر الخاطئة في شكل سلاسل أحرف. ويُعتبر السطر خاطئًا إذا لم يتمكن من توفير الحقول المطلوبة عندما تكون قيمة strict=true.

وستحتوي الفئة أيضًا على طريقتين:

    public int getErreur()

التي تُرجع قيمة السمة الخاصة error.

    public String identite(){

الذي يعرض قيمة الكائن في الصيغة (error, element 1, element 2 …,(l1,l2,…)) حيث العناصر i هي عناصر المتجه الذي تم إنشاؤه من الملف و li هي أرقام الأسطر التي تحتوي على أخطاء.

فيما يلي مثال للاختبار:


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());
  }
}

نتائج التنفيذ:

[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)]

بعض النصائح

  1. تتم معالجة الملف النصي سطراً سطراً. يتم تقسيم السطر إلى حقول باستخدام فئة stringtovector التي تمت مناقشتها سابقاً.

  2. وبالتالي، فإن عناصر المتجه الذي تم إنشاؤه من الملف النصي هي كائنات من نوع stringtovector.

  3. يمكن أن تعتمد طريقة identite الخاصة بـ filetovector على طريقة stringtovector.identite() لعرض عناصرها، وكذلك على طريقة Vector.toString() لعرض أرقام أي أسطر خاطئة.

4.12.5. التمرين 5

نريد إضافة المنشئ التالي إلى فئة filetovector:


    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

أصبحت قائمة الفهارس للحقول المطلوبة الآن في شكل سلسلة (String) بدلاً من مصفوفة من الأعداد الصحيحة.

قد تحتوي السمة الخاصة error على قيمة إضافية:

2: سلسلة مؤشرات الحقول المطلوبة غير صحيحة

فيما يلي اختبار نموذجي:


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());
  }
}

النتائج:

[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)]

بعض النصائح

  1. سنقوم بتحويل السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة tChampVoulus لإعادتها إلى حالة المنشئ السابق.