4. الفئات الشائعة الاستخدام
نقدم في هذا الفصل عددًا من فئات Java الشائعة الاستخدام. تحتوي هذه الفئات على العديد من السمات والأساليب والمُنشِئات. في كل مرة، نقدم جزءًا صغيرًا فقط من الفئات. تتوفر تفاصيل هذه الفئات في دليل Java الذي نقدمه الآن.
4.1. الوثائق
إذا قمت بتثبيت JDK من Sun في المجلد <jdk>، فإن الوثائق متوفرة في المجلد <jdk>\docs:

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


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

لننتقل إلى الرابط Java 2 Platform API:

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

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

نجد فيه
- التسلسل الهرمي الذي توجد فيه الفئة، وهنا java.util.Vector
- قائمة الحقول (السمات) للفئة
- قائمة المنشئات
- قائمة الطرق
بعد ذلك، نقدم فئات متنوعة. ندعو القارئ إلى التحقق بشكل منهجي من التعريف الكامل للفئات المستخدمة.
4.2. فئات الاختبار
تستخدم الأمثلة التالية أحيانًا الفئات personne و enseignant. نذكر هنا تعريفها.
public class personne{
// الاسم، الاسم الأول، العمر
private String prenom;
private String nom;
private int age;
// الشركة المصنعة 1
public personne(String P, String N, int age){
this.prenom=P;
this.nom=N;
this.age=age;
}
// المنشئ 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+")";
}
// الملحقات
public String getPrenom(){
return prenom;
}
public String getNom(){
return nom;
}
public int getAge(){
return age;
}
//المعدلات
public void setPrenom(String P){
this.prenom=P;
}
public void setNom(String N){
this.nom=N;
}
public void setAge(int age){
this.age=age;
}
}
الفئة enseignant مشتقة من الفئة personne ومُعرَّفة على النحو التالي:
class enseignant extends personne{
// السمات
private int section;
// المنشئ
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+")";
}
}
سنستخدم أيضًا فئة etudiant المشتقة من الفئة personne والمعرَّفة على النحو التالي:
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 سلاسل الأحرف. لنفترض أن nom متغير سلسلة أحرف:
String name;
nom هي مرجع لكائن لم يتم تهيئته بعد. يمكن تهيئته بطريقتين:
name="horse" أو name=new String("horse")
الطريقتان متكافئتان. إذا كتبنا لاحقًا name="poisson"، فإن nom تشير عندئذٍ إلى كائن جديد. يتم فقدان الكائن القديم String("cheval") وسيتم استرداد مساحة الذاكرة التي كان يشغلها.
تحتوي الفئة String على العديد من السمات والطرق. فيما يلي بعض منها:
public char charAt(int i) | يعطي الحرف i من السلسلة، حيث الحرف الأول له الرقم 0. وبالتالي فإن String("cheval").charAt(3) يساوي 'v' |
public int compareTo(chaine2) | chaine1.compareTo(chaine2) يقارن chaine1 بـ chaine2 ويعطي 0 إذا كان chaine1=chaine2، و1 إذا كان chaine1>chaine2، و-1 إذا كان chaine1<chaine2 |
public boolean equals(Object anObject) | chaine1.equals(سلسلة2) تُرجع true إذا كانت سلسلة1=سلسلة2، وfalse بخلاف ذلك |
public String toLowerCase() | chaine1.toLowerCase() تحول سلسلة1 إلى أحرف صغيرة |
public String toUpperCase() | chaine1.toUpperCase() تحول السلسلة 1 إلى أحرف كبيرة |
public String trim() | chaine1.trim() يحذف المسافات في بداية ونهاية السلسلة 1 |
public String substring(int beginIndex, int endIndex) | String("chapeau").subString(2,4) تعرض السلسلة "ape" |
public char[] toCharArray() | يسمح بوضع أحرف السلسلة في مصفوفة أحرف |
int length() | عدد أحرف السلسلة |
int indexOf(String chaine2) | تُرجع الموضع الأول لـ chaine2 في السلسلة الحالية أو -1 إذا لم يكن chaine2 موجودًا |
int indexOf(String chaine2, int startIndex) | يعرض الموضع الأول لـ chaine2 في السلسلة الحالية أو -1 إذا لم يكن chaine2 موجودًا. يبدأ البحث من الحرف رقم startIndex. |
int lastIndexOf(String chaine2) | تُرجع آخر موضع لـ chaine2 في السلسلة الحالية أو -1 إذا لم يكن chaine2 موجودًا |
boolean startsWith(String chaine2) | تُرجع true إذا كانت السلسلة الحالية تبدأ بـ chaine2 |
boolean endsWith(String chaine2) | تُرجع القيمة "صحيح" إذا كانت السلسلة الحالية تنتهي بـ chaine2 |
boolean matches(String regex) | تُرجع القيمة "صحيح" إذا كانت السلسلة الحالية تتطابق مع التعبير العادي regex. |
String[] split(String regex) | تتكون السلسلة الحالية من حقول مفصولة بسلسلة أحرف تم نمذجتها بواسطة التعبير العادي regex. تسمح الطريقة split باسترداد الحقول في مصفوفة. |
String replace(char oldChar, char newChar) | يستبدل في السلسلة الحالية الحرف oldChar بالحرف newChar. |
فيما يلي برنامج نموذجي:
// الاستيرادات
import java.io.*;
public class string1{
// فئة توضيحية
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]+"]");
}//لـ
affiche("(\" abc \").trim()=["+" abc ".trim()+"]");
}//Main
// عرض
public static void affiche(String msg){
// عرض رسالة
System.out.println(msg);
}//يعرض
}//فئة
والنتائج التي تم الحصول عليها:
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) | مرجع الكائن رقم index في المتجه - تبدأ الفهارس من 0 |
public final Enumeration elements() | مجموعة عناصر المتجه في شكل تعداد |
public final Object firstElement() | مرجع العنصر الأول في المتجه |
public final Object lastElement() | مرجع العنصر الأخير في المتجه |
public final boolean isEmpty() | تُرجع القيمة "صحيح" إذا كان المتجه فارغًا |
public final void removeElementAt(int index) | يزيل العنصر ذو المؤشر index |
public final void removeAllElements() | يفرغ المتجه من جميع عناصره |
public final String toString() | تُرجع سلسلة تعريف المتجه |
فيما يلي برنامج اختبار:
// الفئات المستوردة
import java.util.*;
public class test1{
// البرنامج الرئيسي main - static - طريقة الفئة
public static void main(String arg[]){
// إنشاء كائنات مثيلات الفئات
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());
// التعدد
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// متجه
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());
}
} // نهاية main
}// نهاية الفئة
لنقوم بتجميع هذا البرنامج:
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() | تُرجع القيمة "صحيح" إذا كان المصفوف فارغًا |
void remove(int index) | يزيل العنصر ذو المؤشر index |
void clear() | يفرغ المصفوفة من جميع عناصرها |
Object[] toArray() | يضع المصفوفة الديناميكية في مصفوفة تقليدية |
String toString() | تُرجع سلسلة تعريف المصفوفة |
فيما يلي برنامج اختبار:
// الفئات المستوردة
import java.util.*;
public class test1{
// البرنامج الرئيسي main - static - طريقة الفئة
public static void main(String arg[]){
// إنشاء كائنات مثيلات الفئات
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);
// التعدد
personne p2=(personne)en;
System.out.println("p2="+p2);
personne p3=(personne)et;
System.out.println("p3="+p3);
// متجه
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);
}
} // نهاية main
}// نهاية الفئة
النتائج التي تم الحصول عليها هي نفسها كما في السابق.
4.6. فئة Arrays
تتيح الفئة java.util.Arrays الوصول إلى طرق ثابتة تسمح بإجراء عمليات مختلفة على المصفوفات، ولا سيما عمليات الفرز والبحث عن العناصر. وفيما يلي بعض هذه الطرق:
static void sort(tableau) | تقوم بفرز tableau باستخدام الترتيب الضمني لنوع بيانات المصفوفة، سواء كانت أرقامًا أو سلاسل أحرف. |
static void sort (Object[] array, Comparator C) | يفرز tableau باستخدام دالة المقارنة C لمقارنة العناصر |
static int binarySearch(مصفوفة، عنصر) | تُرجع موضع élément في tableau أو قيمة <0 بخلاف ذلك. يجب أن يكون المصفوفة مرتبة مسبقًا. |
static int binarySearch(Object[] المصفوفة، Object العنصر، Comparator C) | نفس الشيء ولكن باستخدام دالة المقارنة C لمقارنة عنصرين من المصفوفة. |
فيما يلي مثال أول:
import java.util.*;
public class sort2 implements Comparator{
// فئة داخلية خاصة
private class personne{
private String nom;
private int age;
public personne(String nom, int age){
this.nom=nom; // اسم الشخص
this.age=age; // عمره
}
// استرداد العمر
public int getAge(){
return age;
}
// هوية الشخص
public String toString(){
return ("["+nom+","+age+"]");
}
}; // فئة الشخص
// الشركة المصنعة
public sort2() {
// جدول الأشخاص
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// فرز قائمة الأشخاص
Arrays.sort(amis,this);
// التحقق
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//منشئ
// الوظيفة التي تقارن بين الأشخاص
public int compare(Object o1, Object o2){
// يجب أن تعطي
// -1 إذا كان o1 "أصغر من" o2
// 0 إذا كان o1 "يساوي" o2
// +1 إذا كان o1 "أكبر من" 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;
}//يقارن
// دالة الاختبار
public static void main(String[] arg){
new sort2();
}//يدوي
}//الفئة
دعونا نلقي نظرة على هذا البرنامج. تقوم الدالة main بإنشاء كائن sort2. ومنشئ فئة sort2 هو كما يلي:
// الشركة المصنعة
public sort2() {
// جدول الأشخاص
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// فرز قائمة الأشخاص
Arrays.sort(amis,this);
// التحقق
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//المصمم
المصفوفة المراد فرزها هي مصفوفة من الكائنات personne. تم تعريف الفئة personne بشكل خاص (private) داخل الفئة sort2. لا تعرف الطريقة الثابتة sort للفئة Arrays كيفية فرز مصفوفة من الكائنات personne، لذا نحن مضطرون هنا لاستخدام الصيغة void sort(Object[] obj, Comparator C). Comparator هي واجهة لا تحدد سوى طريقة واحدة:
والتي يجب أن ترجع 0: إذا كان o1=o2، -1: إذا كان o1<o2، +1: إذا كان o1>o2. في النموذج الأولي void sort(Object[] obj, Comparator C)، يجب أن يكون الحجة الثانية C كائنًا ينفذ واجهة Comparator. في المنشئ sort2، تم اختيار الكائن الحالي this:
وهذا يتطلب منا القيام بأمرين:
- الإشارة إلى أن الفئة sort2 تنفذ الواجهة Comparator
- كتابة الدالة compare في الفئة sort2.
وهي كما يلي:
// الوظيفة التي تقارن بين الأشخاص
public int compare(Object o1, Object o2){
// يجب أن تعطي
// -1 إذا كان o1 "أصغر من" o2
// 0 إذا كان o1 "يساوي" o2
// +1 إذا كان o1 "أكبر من" 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;
}//يقارن
لمقارنة كائنين personne، نستخدم هنا العمر (كان من الممكن استخدام الاسم).
نتائج التنفيذ هي كما يلي:
كان من الممكن اتباع طريقة مختلفة لتنفيذ الواجهة Comparator:
import java.util.*;
public class sort2 {
// فئة داخلية خاصة
private class personne{
…….
}; // فئة شخص
// منشئ
public sort2() {
// مصفوفة أشخاص
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// فرز مصفوفة الأشخاص
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//مقارنة
}//فئة
);
// التحقق
for(int i=0;i<3;i++)
System.out.println(amis[i]);
}//منشئ
// الوظيفة التي تقارن الأشخاص
public int compare1(Object o1, Object o2){
// يجب أن ترجع
// -1 إذا كان o1 "أصغر من" o2
// 0 إذا كان o1 "يساوي" o2
// +1 إذا كان o1 "أكبر من" 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;
}//مقارنة1
// main
public static void main(String[] arg){
new sort2();
}//main
}//الفئة
أصبحت تعليمات الفرز كما يلي:
// فرز جدول الأشخاص
Arrays.sort(amis,
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//مقارنة
}//الفصل
);
يجب أن يكون المعامل الثاني للطريقة sort كائنًا ينفذ واجهة Comparator. هنا نقوم بإنشاء كائن من هذا النوع بواسطة new java.util.Comparator() والنص الذي يلي {….} يحدد الفئة التي يتم إنشاء كائن منها. يُطلق على هذه الفئة اسم "فئة مجهولة" لأنها لا تحمل اسمًا. في هذه الفئة المجهولة التي يجب أن تنفذ واجهة Comparator، نحدد الطريقة compare لهذه الواجهة. وتكتفي هذه الطريقة باستدعاء الطريقة compare1 للفئة sort2. وبذلك نعود إلى الحالة السابقة.
لم تعد الفئة sort2 تنفذ واجهة Comparator. وبالتالي يصبح إعلانها كما يلي:
الآن نختبر الطريقة binarySearch للفئة Arrays في المثال التالي:
import java.util.*;
public class sort4 {
// فئة داخلية خاصة
private class personne{
// السمات
private String nom;
private int age;
// منشئ
public personne(String nom, int age){
this.nom=nom; // اسم الشخص
this.age=age; // عمره
}
// استرداد الاسم
public String getNom(){
return nom;
}
// استرداد العمر
public int getAge(){
return age;
}
// هوية الشخص
public String toString(){
return ("["+nom+","+age+"]");
}
}; // فئة الشخص
// المنشئ
public sort4() {
// جدول الأشخاص
personne[] amis=new personne[]{new personne("tintin",100),new personne("milou",80),
new personne("tournesol",40)};
// مقارنات
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//مقارنة
}//فئة
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//مقارنة
}//تصنيف
;
// فرز جدول الأشخاص
Arrays.sort(amis,comparateur1);
// التحقق
for(int i=0;i<3;i++)
System.out.println(amis[i]);
// عمليات البحث
cherche("milou",amis,comparateur2);
cherche("xx",amis,comparateur2);
}//منشئ
// الوظيفة التي تقارن بين الأشخاص
public int compare1(Object o1, Object o2){
// يجب أن تعطي
// -1 إذا كان o1 "أصغر من" o2
// 0 إذا كان o1 "يساوي" o2
// +1 إذا كان o1 "أكبر من" 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
// الوظيفة التي تقارن شخصًا باسم
public int compare2(Object o1, Object o2){
// o1 هو شخص
// o2 هو سلسلة، الاسم اسم2 لشخص
// يجب أن تعطي
// -1 إذا كان o1.nom "أصغر من" اسم2
// 0 إذا كان o1.nom "يساوي" اسم2
// +1 إذا كان o1.nom "أكبر من" اسم2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//مقارنة2
public void cherche(String ami,personne[] amis, Comparator comparateur){
// البحث عن صديق في جدول الأصدقاء
int position=Arrays.binarySearch(amis,ami,comparateur);
// تم العثور عليه؟
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//البحث
// اليد
public static void main(String[] arg){
new sort4();
}//يد
}//الفصل
هنا، اتبعنا طريقة مختلفة قليلاً عن الأمثلة السابقة. تم إنشاء الكائنين Comparator اللازمين للطريقتين sort و binarySearch وتعيينهما للمتغيرين comparateur1 و comparateur2.
// مقارنات
java.util.Comparator comparateur1=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare1(o1,o2);
}//مقارنة
}//الفصل
;
java.util.Comparator comparateur2=
new java.util.Comparator(){
public int compare(Object o1, Object o2){
return compare2(o1,o2);
}//مقارنة
}//فئة
;
يتم إجراء بحث ثنائي على الجدول amis مرتين في منشئ sort4:
تتلقى الطريقة cherche جميع المعلمات التي تحتاجها لاستدعاء الطريقة binarySearch:
public void cherche(String ami,personne[] amis, Comparator comparateur){
// البحث عن صديق في قائمة الأصدقاء
int position=Arrays.binarySearch(amis,ami,comparateur);
// تم العثور عليه؟
if(position>=0)
System.out.println(ami + " a " + amis[position].getAge() + " ans");
else System.out.println(ami + " n'existe pas dans le tableau");
}//يبحث
تعمل الطريقة binarySearch مع المقارن comparateur2 الذي يستدعي بدوره الطريقة compare2 من الفئة sort4. تُرجع الطريقة rend موضع الاسم المطلوب في الجدول إن وجد، أو عددًا <0 في حالة عدم وجوده. تُستخدم الطريقة compare2 لمقارنة كائن personne باسم من النوع String.
// الوظيفة التي تقارن شخصًا باسم
public int compare2(Object o1, Object o2){
// o1 هو شخص
// o2 هو سلسلة، الاسم اسم2 لشخص
// يجب أن يعطي
// -1 إذا كان o1.nom "أصغر من" اسم2
// 0 إذا كان o1.nom "يساوي" اسم2
// +1 إذا كان o1.nom "أكبر من" اسم2
personne p1=(personne)o1;
String nom1=p1.getNom();
String nom2=(String)o2;
return nom1.compareTo(nom2);
}//مقارنة2
على عكس الطريقة sort، لا تستقبل الطريقة binarySearch كائنين personne، بل كائن personne وكائن String بهذا الترتيب. المعلمة الأولى هي عنصر من المصفوفة amis، والثانية هي اسم الشخص المطلوب.
4.7. فئة Enumeration
Enumeration هي واجهة وليست فئة. وتحتوي على الطرق التالية:
public abstract boolean hasMoreElements() | تُرجع القيمة "صحيح" إذا كان التعداد لا يزال يحتوي على عناصر |
public abstract Object nextElement() | تُرجع مرجع العنصر التالي في التعداد |
كيف يتم استخدام التعداد؟ بشكل عام كما يلي:
Enumeration e=… // يتم استرداد كائن enumeration
while(e.hasMoreElements()){
// استخدام العنصر e.nextElement()
}
إليك مثال:
// الفئات المستوردة
import java.util.*;
public class test1{
// البرنامج الرئيسي main - static - طريقة الفئة
public static void main(String arg[]){
// إنشاء كائنات مثيلات الفئات
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());
// التعدد
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// متجه
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());
}
// تعداد
Enumeration E=V.elements();
i=0;
while(E.hasMoreElements()){
p2=(personne) E.nextElement();
System.out.println("V["+i+"]="+p2.toString());
i++;
}
}// نهاية main
}//نهاية الفئة
ونحصل على النتائج التالية:
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 |
.. | ... |
المفاتيح فريدة، c.a.d. بحيث لا يمكن أن يكون هناك مفتاحان متطابقان. فيما يلي الطرق والخصائص الرئيسية لفئة Hashtable:
public Hashtable() | منشئ - ينشئ قاموسًا فارغًا |
public int size() | عدد العناصر في القاموس - حيث يمثل العنصر زوجًا (مفتاح، قيمة) |
public Object put(Object key, Object value) | يضيف الزوج (key, value) إلى القاموس |
public Object get(Object key) | يسترد الكائن المرتبط بالمفتاح key أو null إذا كان المفتاح key غير موجود |
public boolean containsKey(Object key) | صحيح إذا كان المفتاح key موجودًا في القاموس |
public boolean contains(Object value) | صحيح إذا كانت القيمة value موجودة في القاموس |
public Enumeration keys() | تُرجع مفاتيح القاموس في شكل تعداد |
public Object remove(Object key) | يزيل الزوج (المفتاح، القيمة) حيث المفتاح=key |
public String toString() | يحدد القاموس |
فيما يلي مثال:
// الفئات المستوردة
import java.util.*;
public class test1{
// البرنامج الرئيسي main - static - طريقة الفئة
public static void main(String arg[]){
// إنشاء كائنات مثيلات الفئات
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());
// التعدد
personne p2=(personne)en;
System.out.println("p2="+p2.toString());
personne p3=(personne)et;
System.out.println("p3="+p3.toString());
// قاموس
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++;
}
}//نهاية main
}//نهاية الفئة
النتائج التي تم الحصول عليها هي التالية:
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، c.a.d. تدفق كتابة (في ملف، على الشبكة، ...) |
PrintWriter(Writer out, boolean autoflush) | نفس الشيء. الحجة الثانية تدير التخزين المؤقت للسطور. عندما تكون القيمة "false" (القيمة الافتراضية)، تمر السطور المكتوبة في الملف عبر مخزن مؤقت في الذاكرة. وعندما يمتلئ هذا المخزن، يتم الكتابة في الملف. وهذا يحسن الوصول إلى القرص. ومع ذلك، في بعض الأحيان، يكون هذا السلوك غير مرغوب فيه، لا سيما عند الكتابة على الشبكة. |
الطرق المفيدة لفئة PrintWriter هي التالية:
void print(Type T) | تكتب البيانات T (String، int، ….) |
void println(Type T) | كما سبق مع إضافة علامة نهاية السطر |
void flush() | يفرغ المخزن المؤقت إذا لم نكن في وضع autoflush |
void close() | يغلق تدفق الكتابة |
فيما يلي برنامج يكتب بضعة أسطر في ملف نصي:
// الاستيرادات
import java.io.*;
public class ecrire{
public static void main(String[] arg){
// فتح الملف
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// الكتابة في الملف
try{
fic.println("Jean,Dupont,27");
fic.println("Pauline,Garcia,24");
fic.println("Gilles,Dumond,56");
} catch (Exception e){
Erreur(e,3);
}
// إغلاق الملف
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// نهاية main
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//خطأ
}//فئة
الملف out الذي تم الحصول عليه عند التنفيذ هو التالي:
4.9.2. قراءة
لقراءة محتوى ملف ما، يجب أن يكون لديك دفق قراءة مرتبط بالملف. يمكن استخدام الفئة FileReader والمُنشئ التالي لهذا الغرض:
FileReader(String اسم_الملف) | يفتح تدفق قراءة من الملف المحدد. يطلق استثناءً إذا فشلت العملية. |
تحتوي الفئة FileReader على عدد من الطرق لقراءة ملف، وهي طرق موروثة من الفئة Reader. لقراءة أسطر النص في ملف نصي، يفضل استخدام الفئة BufferedReader مع المنشئ التالي:
BufferedReader(Reader in) | يفتح دفق قراءة مخزن مؤقتًا من دفق إدخال in. يمكن أن يأتي هذا الدفق من النوع Reader من لوحة المفاتيح أو من ملف أو من الشبكة، ... |
الطرق المفيدة للفئة BufferedReader هي التالية:
int read() | يقرأ حرفًا |
String readLine() | يقرأ سطرًا من النص |
int read(char[] buffer, int offset, int taille) | يقرأ taille حرفًا من الملف ويضعها في المصفوفة buffer بدءًا من الموضع offset. |
void close() | يغلق تدفق القراءة |
فيما يلي برنامج يقرأ محتوى الملف الذي تم إنشاؤه مسبقًا:
// الفئات المستوردة
import java.util.*;
import java.io.*;
public class lire{
public static void main(String[] arg){
personne p=null;
// فتح الملف
BufferedReader IN=null;
try{
IN=new BufferedReader(new FileReader("out"));
} catch (Exception e){
Erreur(e,1);
}
// البيانات
String ligne=null;
String[] champs=null;
String prenom=null;
String nom=null;
int age=0;
// معالجة الأخطاء المحتملة
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));
}// نهاية while
} catch (Exception e){
Erreur(e,2);
}
// إغلاق الملف
try{
IN.close();
} catch (Exception e){
Erreur(e,3);
}
}// نهاية main
// خطأ
public static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}
}// نهاية الفئة
يؤدي تشغيل البرنامج إلى النتائج التالية:
4.9.3. حفظ كائن شخص
نطبق ما رأيناه للتو لتزويد الفئة personne بطريقة تسمح بحفظ سمات شخص ما في ملف. نضيف الطريقة sauveAttributs في تعريف الفئة personne:
// ------------------------------
// حفظ في ملف نصي
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
قبل تعريف الفئة personne، لا تنسَ استيراد الحزمة java.io:
تستقبل الطريقة sauveAttributs كمعلمة وحيدة التدفق PrintWriter الذي يجب أن تكتب فيه. قد يكون برنامج الاختبار كما يلي:
// استيراد
import java.io.*;
// استيراد شخص؛
public class sauver{
public static void main(String[] arg){
// فتح الملف
PrintWriter fic=null;
try{
fic=new PrintWriter(new FileWriter("out"));
} catch (Exception e){
Erreur(e,1);
}
// الكتابة في الملف
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);
}
// إغلاق الملف
try{
fic.close();
} catch (Exception e){
Erreur(e,2);
}
}// نهاية main
// خطأ
private static void Erreur(Exception e, int code){
System.err.println("Erreur : "+e);
System.exit(code);
}//خطأ
}//فئة
لنقوم بتجميع هذا البرنامج وتشغيله:
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 اسم_الملف, String الوضع) | منشئ - يفتح الملف المحدد بالوضع المحدد. ويأخذ هذا الوضع قيمه من: r: فتح للقراءة rw: فتح للقراءة والكتابة |
void writeTTT(TTT قيمة) | يكتب القيمة في الملف. يمثل TTT نوع القيمة. يتم كتابة تمثيل الذاكرة للقيمة كما هو في الملف. وبذلك نجد writeBoolean، writeByte، writeInt، writeDouble، writeLong، writeFloat،... لكتابة سلسلة، نستخدم writeBytes(String chaine). |
يقرأ TTT readTTT() | يقرأ ويعرض قيمة من النوع TTT. وهكذا نجد readBoolean، readByte، readInt، readDouble، readLong، readFloat،... تقرأ الطريقة read() بايتًا واحدًا. |
طول الملف | حجم الملف بالبايت |
long getFilePointer() | الموضع الحالي لمؤشر الملف |
void seek(long pos) | يضع مؤشر الملف عند البايت pos |
4.10.2. فئة article
ستستخدم جميع الأمثلة التالية الفئة article التالية:
// هيكل المادة
private static class article{
// يتم تعريف البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة المادة
ستكون فئة java article أعلاه معادلة للبنية article التالية في لغة C
struct article{
char code[4];
char nom[20];
double prix;
int stockActuel;
int stockMinimum;
}//البنية
وبذلك سنحدد الرمز بـ 4 أحرف والاسم بـ 20 حرفًا.
4.10.3. كتابة سجل
يكتب البرنامج التالي مقالًا في ملف يسمى "data":
// الفئات المستوردة
import java.io.*;
public class test1{
// اختبار كتابة بنية (بالمعنى المستخدم في لغة C) في ملف ثنائي
// هيكل المادة
private static class article{
// نحدد البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة article
public static void main(String arg[]){
// يتم تعريف الملف الثنائي الذي سيتم تخزين المقالات فيه
RandomAccessFile fic=null;
// يتم تعريف مادة
article art=new article();
art.code="a100";
art.nom="velo";
art.prix=1000.80;
art.stockActuel=100;
art.stockMinimum=10;
// يتم تعريف الملف
try{
fic=new RandomAccessFile("data","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// يتم الكتابة
try{
ecrire(fic,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement",2);
}//try-catch
// انتهى
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}//main
// طريقة الكتابة
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// الرمز
fic.writeBytes(art.code);
// الاسم محدد بـ 20 حرفًا
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);
// السعر
fic.writeDouble(art.prix);
// المخزون
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// نهاية الكتابة
// ------------------------خطأ
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// نهاية الخطأ
}// نهاية الفئة
البرنامج التالي هو الذي يسمح لنا بالتحقق من أن التنفيذ قد تم بشكل صحيح.
4.10.4. قراءة سجل
// الفئات المستوردة
import java.io.*;
public class test2{
// اختبار كتابة بنية (بالمعنى المستخدم في لغة C) في ملف ثنائي
// بنية article
private static class article{
// نحدد البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة article
public static void main(String arg[]){
// يتم تعريف الملف الثنائي الذي سيتم تخزين المقالات فيه
RandomAccessFile fic=null;
// يتم فتح الملف للقراءة
try{
fic=new RandomAccessFile("data","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data",1);
}//try-catch
// يتم قراءة المادة الوحيدة من الملف
article art=new article();
try{
lire(fic,art);
} catch (IOException E){
erreur("Erreur lors de la lecture de l'enregistrement",2);
}//try-catch
// نقوم بعرض السجل الذي تمت قراءته
affiche(art);
// انتهى
try{
fic.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data",2);
}//try-catch
}// نهاية اليد
// طريقة القراءة
public static void lire(RandomAccessFile fic, article art) throws IOException{
// قراءة الرمز
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// الاسم
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// السعر
art.prix=fic.readDouble();
// المخزون
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// نهاية الكتابة
// ---------------------عرض
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);
}// نهاية العرض
// ------------------------خطأ
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// نهاية الخطأ
}// نهاية الفئة
نتائج التنفيذ هي كما يلي:
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
// الفئات المستوردة
import java.io.*;
import java.util.*;
public class test3{
// ملف نصي --> ملف ثنائي
// هيكل المقالة
private static class article{
// نحدد البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة المقالة
public static void main(String arg[]){
// يتم تعريف الملف الثنائي الذي سيتم تخزين المقالات فيه
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","rw");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin",1);
}
// يتم أخذ البيانات من ملف نصي
BufferedReader dataTxt=null;
try{
dataTxt=new BufferedReader(new FileReader("data.txt"));
} catch (IOException E){
erreur("Impossible d'ouvrir le fichier data.txt",2);
}
// ملف .txt --> ملف .bin
String ligne=null;
String[] champs=null;
int numLigne=0;
String champ=null;
article art=new article(); // المادة المراد إنشاؤها
try{
while((ligne=dataTxt.readLine())!=null){
// سطر من +
numLigne++;
// التقسيم إلى حقول
champs=ligne.split(":");
// يلزم 5 حقول
if(champs.length!=5)
erreur("Ligne "+numLigne+" erronée dans data.txt",3);
//رمز
art.code=champs[0];
if(art.code.length()!=4)
erreur("Code erroné en ligne "+numLigne+" du fichier data.txt",12);
// الاسم، الاسم الأول
art.nom=champs[1];
// السعر
try{
art.prix=Double.parseDouble(champs[2]);
} catch (Exception E){
erreur("Prix erroné en ligne "+numLigne+" du fichier data.txt",4);
}
// المخزون الحالي
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// المخزون الحالي
try{
art.stockActuel=Integer.parseInt(champs[3]);
} catch (Exception E){
erreur("Stock actuel erroné en ligne "+ numLigne + " du fichier data.txt",5);
}
// يتم كتابة السجل
try{
ecrire(dataBin,art);
} catch (IOException E){
erreur("Erreur lors de l'écriture de l'enregistrement "+numLigne,7);
}
// الانتقال إلى السطر التالي
}// نهاية while
} catch (IOException E){
erreur("Erreur lors de la lecture du fichier data.txt après la ligne "+numLigne,8);
}
// انتهى
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);
}
}// نهاية main
// طريقة الكتابة
public static void ecrire(RandomAccessFile fic, article art) throws IOException{
// الرمز
fic.writeBytes(art.code);
// الاسم محدد بـ 20 حرفًا
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);
// السعر
fic.writeDouble(art.prix);
// المخزون
fic.writeInt(art.stockActuel);
fic.writeInt(art.stockMinimum);
}// نهاية الكتابة
// ------------------------خطأ
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// نهاية الخطأ
}// نهاية الفئة
البرنامج التالي يسمح بالتحقق من أن هذا البرنامج قد عمل بشكل صحيح.
4.10.6. تحويل ثنائي --> نص
يقوم البرنامج التالي بقراءة محتوى الملف الثنائي data.bin الذي تم إنشاؤه مسبقًا، ويضع محتواه في الملف النصي data.text. إذا سارت الأمور على ما يرام، يجب أن يكون الملف data.text مطابقًا للملف الأصلي data.txt.
// الفئات المستوردة
import java.io.*;
import java.util.*;
public class test5{
// ملف نصي --> ملف ثنائي
// هيكل المقالة
private static class article{
// نحدد البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة المقالة
// الرئيسية
public static void main(String arg[]){
// يتم تعريف الملف الثنائي الذي سيتم تخزين المقالات فيه
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// تُكتب البيانات في ملف نصي
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 --> ملف .text
article art=new article(); // المادة المراد إنشاؤها
// يتم استغلال الملف الثنائي
int numRecord=0;
long l=0; // حجم الملف
try{
l=dataBin.length();
} catch (IOException e){
erreur("Erreur lors du calcul de la longueur du fichier data.bin",2);
}
long pos=0; // الموضع الحالي في الملف
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
// ما لم يتم تجاوز نهاية الملف
while(pos<l){
// قراءة السجل الحالي واستخدامه
numRecord++;
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
affiche(art);
// كتابة سطر النص المقابل في dataTxt
dataTxt.println(art.code.trim()+":"+art.nom.trim()+":"+art.prix+":"+art.stockActuel+":"+art.stockMinimum);
// هل نواصل؟
try{
pos=dataBin.getFilePointer();
} catch (IOException e){
erreur("Erreur lors de la lecture de la position courante dans data.bin",2);
}
}// نهاية while
// انتهى
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);
}
}// نهاية main
// طريقة القراءة
public static void lire(RandomAccessFile fic, article art) throws IOException{
// قراءة الكود
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// الاسم
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// السعر
art.prix=fic.readDouble();
// المخزون
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// نهاية الكتابة
// ---------------------عرض
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);
}// نهاية العرض
// ------------------------خطأ
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// نهاية الخطأ
}// نهاية الفئة
فيما يلي مثال على التنفيذ:
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.
// الفئات المستوردة
import java.io.*;
import java.util.*;
public class test6{
// ملف نصي --> ملف ثنائي
// هيكل المقالة
private static class article{
// نحدد البنية
public String code;
public String nom;
public double prix;
public int stockActuel;
public int stockMinimum;
}//فئة المقالة
// الرئيسية
public static void main(String[] args){
// التحقق من الحجج
int nbArguments=args.length;
String syntaxe="syntaxe : pg numéro_de_fiche";
if(nbArguments!=1)
erreur(syntaxe,20);
// التحقق من رقم السجل
int numRecord=0;
try{
numRecord=Integer.parseInt(args[0]);
} catch(Exception e){
erreur(syntaxe+"\nNuméro de fiche incorrect",21);
}
// يتم فتح الملف الثنائي للقراءة
RandomAccessFile dataBin=null;
try{
dataBin=new RandomAccessFile("data.bin","r");
} catch (Exception E){
erreur("Impossible d'ouvrir le fichier data.bin en lecture",1);
}
// التحديد على السجل المطلوب
try{
dataBin.seek((numRecord-1)*40);
} catch (Exception e){
erreur("La fiche "+numRecord+" n'existe pas",23);
}
// قراءتها
article art=new article();
try{
lire(dataBin,art);
} catch (Exception e){
erreur("Erreur lors de la lecture de l'enregistrement "+numRecord,2);
}
// عرضها
affiche(art);
// انتهى الأمر
try{
dataBin.close();
} catch (Exception E){
erreur("Impossible de fermer le fichier data.bin",2);
}//try-catch
}// نهاية main
// طريقة القراءة
public static void lire(RandomAccessFile fic, article art) throws IOException{
// قراءة الكود
art.code="";
for(int i=0;i<4;i++) art.code+=(char)fic.readByte();
// الاسم
art.nom="";
for(int i=0;i<20;i++) art.nom+=(char)fic.readByte();
art.nom=art.nom.trim();
// السعر
art.prix=fic.readDouble();
// المخزون
art.stockActuel=fic.readInt();
art.stockMinimum=fic.readInt();
}// نهاية الكتابة
// ---------------------عرض
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);
}// نهاية العرض
// ------------------------خطأ
public static void erreur(String msg, int exitCode){
System.err.println(msg);
System.exit(exitCode);
}// نهاية الخطأ
}// نهاية الفئة
فيما يلي أمثلة على التنفيذ:
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.util.regex باستخدام التعبيرات العادية. تسمح هذه التعبيرات باختبار تنسيق سلسلة أحرف. وبذلك يمكن التحقق من أن سلسلة تمثل تاريخًا هي بالفعل بتنسيق يي/ش/س. نستخدم لهذا الغرض نموذجًا ونقارن السلسلة بهذا النموذج. وهكذا في هذا المثال، يجب أن تكون j و m و a أرقامًا. يكون نموذج تنسيق التاريخ الصحيح هو "\d\d/\d\d/\d\d" حيث يشير الرمز \d إلى رقم. الرموز التي يمكن استخدامها في النموذج هي التالية (وثائق Microsoft):
الحرف | الوصف |
\ | يُشير إلى الحرف التالي على أنه حرف خاص أو حرف عادي. على سبيل المثال، "n" يُشير إلى الحرف "n". "\n" يُشير إلى حرف السطر الجديد. التسلسل "\\" يُشير إلى "\"، بينما "\(" يُشير إلى "(". |
^ | يمثل بداية الإدخال. |
$ | يمثل نهاية الإدخال. |
* | يعني الحرف السابق صفر مرة أو عدة مرات. لذا، فإن "zo*" تعني "z" أو "zoo". |
+ | يتطابق مع الحرف السابق مرة واحدة أو عدة مرات. وبالتالي، فإن "zo+" يتطابق مع "zoo"، ولكنه لا يتطابق مع "z". |
? | يتطابق مع الحرف السابق صفر أو مرة واحدة. على سبيل المثال، "a?ve?" يتطابق مع "ve" في "lever". |
. | يتطابق مع أي حرف فردي، باستثناء حرف السطر الجديد. |
(نموذج) | يبحث عن modèle ويحفظ المطابقة. يمكن استخراج السلسلة الفرعية المطابقة من مجموعة 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" في "verbe". |
\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" يعادل حرفين متطابقين متتاليين. |
|
يمكن أن يتواجد عنصر في نموذج في نسخة واحدة أو أكثر. لنأخذ بعض الأمثلة حول الرمز \d الذي يمثل رقمًا واحدًا:
القالب | المعنى |
\d | رقم واحد |
\d? | رقم واحد أو صفر |
\d* | رقم واحد أو أكثر |
\d+ | رقم واحد أو أكثر |
\d{2} | رقمان |
\d{3,} | 3 أرقام على الأقل |
\d{5,7} | بين 5 و7 أرقام |
لنتخيل الآن النموذج القادر على وصف التنسيق المتوقع لسلسلة أحرف:
السلسلة المطلوبة | النموذج |
تاريخ بتنسيق يي/ش/س | \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* |
سلسلة تحتوي على الكلمة juste | \bjuste\b |
يمكن تحديد مكان البحث عن النمط في السلسلة:
النمط | المعنى |
^نموذج | يبدأ النموذج السلسلة |
النمط$ | ينهي النموذج السلسلة |
^النمط$ | يبدأ النموذج وينهي السلسلة |
النمط | يتم البحث عن النمط في كل أجزاء السلسلة بدءًا من بدايتها. |
السلسلة المطلوبة | النمط |
سلسلة تنتهي بعلامة تعجب | !$ |
سلسلة تنتهي بنقطة | \.$ |
سلسلة تبدأ بالتسلسل // | ^// |
سلسلة تتكون من كلمة واحدة فقط قد تسبقها أو تليها مسافات | ^\s*\w+\s*$ |
سلسلة تتكون من كلمتين قد تسبقهما أو تتبعهما مسافات | ^\s*\w+\s*\w+\s*$ |
سلسلة تحتوي على الكلمة secret | \bsecret\b |
يمكن "استرداد" المجموعات الفرعية لنموذج ما. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نموذج معين، بل يمكننا أيضًا استرداد العناصر الموجودة في هذه السلسلة والتي تتطابق مع المجموعات الفرعية للنموذج التي تم وضعها بين قوسين. لذا، إذا قمنا بتحليل سلسلة تحتوي على تاريخ ي/ش/س، وأردنا أيضًا استرداد العناصر ي، ش، س من هذا التاريخ، فسنستخدم النموذج (\d\d)/(\d\d)/(\d\d).
4.11.2. التحقق من مطابقة سلسلة مع نموذج معين
تسمح الفئة Pattern بالتحقق من مطابقة سلسلة لنموذج معين. وللقيام بذلك، نستخدم الطريقة الثابتة
مع: modèle: النموذج المراد التحقق منه، chaine: السلسلة المراد مقارنتها بالنموذج. والنتيجة هي القيمة المنطقية true إذا كانت السلسلة تتطابق مع النموذج، وfalse في حالة عدم التطابق.
فيما يلي مثال:
import java.io.*;
import java.util.regex.*;
// إدارة التعبيرات العادية
public class regex1 {
public static void main(String[] args){
// نمط تعبير عادي
String modèle1="^\\s*\\d+\\s*$";
// مقارنة نسخة بالنموذج
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);
}//عرض
}//تصنيف
ونتيجة التنفيذ:
تجدر الإشارة إلى أنه في النمط "^\s*\d+\s*$" يجب تكرار الحرف \ مرتين بسبب الطريقة الخاصة التي تفسر بها Java هذا الحرف. لذلك نكتب: String نمط1="^\\s*\\d+\\s*$";
4.11.3. البحث عن جميع عناصر سلسلة تتطابق مع نموذج
لنأخذ النموذج "\d+" والسلسلة " 123 456 789 " كمثال. نجد النموذج في ثلاثة أماكن مختلفة من السلسلة. تسمح فئتا Pattern و Matcher باسترداد التكرارات المختلفة لنموذج ما في سلسلة. الفئة Pattern هي الفئة التي تدير التعبيرات العادية. يتطلب التعبير العادي المستخدم أكثر من مرة أن يتم "تجميعه". وهذا يسرع عمليات البحث عن النموذج في السلاسل. تقوم الطريقة الثابتة compile بهذه المهمة:
تأخذ هذه الطريقة سلسلة النموذج كمعلمة وتُرجع كائن Pattern. لمقارنة نموذج كائن Pattern بسلسلة أحرف، نستخدم الفئة Matcher. تسمح هذه الفئة بمقارنة نموذج بسلسلة أحرف. من كائن Pattern، يمكن الحصول على كائن من النوع Matcher باستخدام الطريقة matcher:
input هي سلسلة الأحرف التي يجب مقارنتها بالنموذج.
وبالتالي، لمقارنة النموذج "\d+" بالسلسلة " 123 456 789 "، يمكن إنشاء كائن Matcher بالطريقة التالية:
انطلاقًا من الكائن résultats السابق، سنتمكن من استرداد المرات المختلفة لظهور النموذج في السلسلة. وللقيام بذلك، نستخدم طرق suivantes من فئة Matcher:
تبحث الطريقة 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.*;
// إدارة التعبيرات العادية
public class regex2 {
public static void main(String[] args){
// تكررات متعددة للنموذج في النسخة
String modèle2="\\d+";
Pattern regex2=Pattern.compile(modèle2);
String exemplaire3=" 123 456 789";
// البحث عن تكرارات النموذج في النسخة
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);
}//يعرض
}//تصنيف
نتائج التنفيذ:
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. استرداد أجزاء من نموذج
يمكن "استرداد" مجموعات فرعية من نموذج. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نموذج معين، بل يمكننا أيضًا استرداد العناصر الموجودة في هذه السلسلة والتي تتطابق مع المجموعات الفرعية للنموذج التي تم وضعها بين قوسين. لذا، إذا قمنا بتحليل سلسلة تحتوي على تاريخ ي/ش/س، وأردنا أيضًا استرداد العناصر ي، ش، س من هذا التاريخ، فسنستخدم النموذج (\d\d)/(\d\d)/(\d\d).
لننظر إلى المثال التالي:
import java.io.*;
import java.util.regex.*;
// إدارة التعبيرات العادية
public class regex3 {
public static void main(String[] args){
// التقاط العناصر في النموذج
String modèle3="(\\d\\d):(\\d\\d):(\\d\\d)";
Pattern regex3=Pattern.compile(modèle3);
String exemplaire4="Il est 18:05:49";
// التحقق من النموذج
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// النسخة تتطابق مع النموذج
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// يتم عرض المجموعات
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//for
}else{
// النسخة لا تتطابق مع النموذج
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
}//الرئيسي
public static void affiche(String msg){
System.out.println(msg);
}//يعرض
}//الفئة
يؤدي تشغيل هذا البرنامج إلى النتائج التالية:
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
يوجد التغيير في الجزء التالي من الكود:
// التحقق من النموذج
Matcher résultat=regex3.matcher(exemplaire4);
if (résultat.find()){
// النسخة تتطابق مع النموذج
affiche("L'exemplaire ["+exemplaire4+"] correspond au modèle ["+modèle3+"]");
// يتم عرض المجموعات
for (int i=0;i<=résultat.groupCount();i++){
affiche("groupes["+i+"]=["+résultat.group(i)+"] en position "+résultat.start(i));
}//من أجل
}else{
// النسخة لا تتطابق مع النموذج
affiche("L'exemplaire["+exemplaire4+" ne correspond pas au modèle ["+modèle3+"]");
}
يتم مقارنة السلسلة exemplaire4 بالنموذج regex3 من خلال الطريقة find. ثم يتم العثور على مثيل للنموذج regex3 في السلسلة exemplaire4. إذا كان النموذج يتضمن مجموعات فرعية محاطة بأقواس، فإن هذه المجموعات تكون متاحة بفضل طرق متنوعة من الفئة 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.*;
// إدارة التعبيرات العادية
public class regex4 {
public static void main(String[] args){
// البيانات
String modèle=null,chaine=null;
Pattern regex=null;
BufferedReader IN=null;
Matcher résultats=null;
int nbOccurrences=0;
// إدارة الأخطاء
try{
// يُطلب من المستخدم النماذج والنسخ التي يجب مقارنتها بهذه
while(true){
// تدفق الإدخال
IN=new BufferedReader(new InputStreamReader(System.in));
// يُطلب النموذج
System.out.print("Tapez le modèle à tester ou fin pour arrêter :");
modèle=IN.readLine();
// انتهى؟
if(modèle.trim().toLowerCase().equals("fin")) break;
// يتم إنشاء التعبير العادي
regex=Pattern.compile(modèle);
// يُطلب من المستخدم النسخ المراد مقارنتها بالنموذج
while(true){
System.out.print("Tapez la chaîne à comparer au modèle ["+modèle+"] ou fin pour arrêter :");
chaine=IN.readLine();
// انتهى؟
if(chaine.trim().toLowerCase().equals("fin")) break;
// يتم إنشاء كائن المطابقة
résultats=regex.matcher(chaine);
// نبحث عن تكرارات النموذج
nbOccurrences=0;
while(résultats.find()){
// وجدنا مثيلًا
nbOccurrences++;
// يتم عرضها
System.out.println("J'ai trouvé la correspondance ["+résultats.group()
+"] en position "+résultats.start());
// عرض العناصر الفرعية
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
// السلسلة التالية
}//while(résultats.find())
// هل تم العثور على مثيل واحد على الأقل؟
if(nbOccurrences==0){
System.out.println("Je n'ai pas trouvé de correspondance au modèle ["+modèle+"]");
}//if
// النمط التالي
}//while(true)
}//while(true)
}catch(Exception ex){
// خطأ
System.err.println("Erreur : "+ex.getMessage());
// نهاية مع خطأ
System.exit(1);
}//محاولة-التقاط
// نهاية
System.exit(0);
}//Main
}//فئة
فيما يلي مثال على التنفيذ:
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)
يتم تقسيم السلسلة input إلى حقول، يتم فصلها بفاصل يتوافق مع نموذج الكائن Pattern الحالي. لاسترداد الحقول من سطر يكون فاصل الحقول فيه هو الفاصلة التي تسبقها أو تتبعها أي عدد من المسافات، نكتب:
// سطر
String ligne="abc ,, def , ghi";
// نموذج
Pattern modèle=Pattern.compile("\\s*,\\s*");
// تقسيم السطر إلى حقول
String[] champs=modèle.split(ligne);
يمكن الحصول على نفس النتيجة باستخدام الطريقة split من الفئة String:
public String[] split(String regex)
فيما يلي برنامج اختباري:
import java.io.*;
import java.util.regex.*;
// إدارة التعبيرات العادية
public class split1 {
public static void main(String[] args){
// سطر
String ligne="abc ,, def , ghi";
// قالب
Pattern modèle=Pattern.compile("\\s*,\\s*");
// تفكيك السطر إلى حقول
String[] champs=modèle.split(ligne);
// العرض
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
// طريقة أخرى للقيام بذلك
champs=ligne.split("\\s*,\\s*");
// العرض
for(int i=0;i<champs.length;i++){
System.out.println("champs["+i+"]=["+champs[i]+"]");
}//for
}//الرئيسية
}//فئة
نتائج التنفيذ:
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 … من أجل إنشاء الكيانات التالية:
optionsValides | قاموس (Hashtable) تكون مفاتيحه هي الخيارات oi الصالحة. القيمة المرتبطة بالمفتاح oi هي متجه (Vector) تكون عناصره هي القيم v1 v2 … المرتبطة بالخيار -oi |
optionsInvalides | قاموس (Hashtable) مفاتيحه هي خيارات oi غير الصالحة. القيمة المرتبطة بالمفتاح oi هي متجه (Vector) عناصره هي القيم v1 v2 … المرتبطة بخيار -oi |
optionsSans | سلسلة (String) تعطي قائمة بالقيم vi غير المرتبطة بخيار |
erreur | عدد صحيح يساوي 0 إذا لم تكن هناك أخطاء في سطر الحجج، وإلا فإنه يساوي: 1: توجد معلمات استدعاء غير صالحة 2: توجد خيارات غير صالحة 4: توجد قيم غير مرتبطة بخيارات إذا كان هناك عدة أنواع من الأخطاء، يتم تجميع هذه القيم. |
يمكن إنشاء كائن خيارات بأربع طرق مختلفة:
public options (String arguments, String optionsAcceptables)
arguments | سطر الحجج -o1 v1 v2 ... -o2 v3 v4 … المراد تحليله |
optionsAcceptables | قائمة الخيارات oi المقبولة |
مثال على الاستدعاء: 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)
ستتضمن فئة الخيارات الواجهة التالية (أدوات الوصول):
تُرجع مرجع الجدول optionsValides الذي تم إنشاؤه عند إنشاء كائن الخيارات
يعرض مرجع المصفوفة optionsInvalides التي تم إنشاؤها عند إنشاء كائن الخيارات
يعرض مرجع السلسلة optionsSans التي تم إنشاؤها عند إنشاء كائن الخيارات
يعرض قيمة سمة الخطأ التي تم إنشاؤها عند إنشاء كائن الخيارات
إذا لم تكن هناك أخطاء، يعرض قيم سمات optionsValides، optionsInvalides، optionsSans أو يعرض رقم الخطأ في حالة وجود أخطاء.
فيما يلي برنامج نموذجي:
import java.io.*;
//خيارات الاستيراد؛
public class test1{
public static void main (String[] arg){
// فتح دفق الإدخال
String ligne;
BufferedReader IN=null;
try{
IN=new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e){
affiche(e);
System.exit(1);
}
// قراءة معلمات منشئ 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));
}// نهاية while
}//نهاية main
public static void affiche(Exception e){
System.err.println("Erreur : "+e);
}
}//نهاية الفئة
بعض النتائج:
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:
وسيكون له البناء التالي:
private void stringtovector(String S, String separateur, int[] tChampsVoulus,
boolean strict){
// إنشاء متجه بحقول السلسلة S
// تتكون هذه السلسلة من حقول مفصولة بفاصل
// إذا كان الفاصل = null، فإن السلسلة تشكل حقلًا واحدًا فقط
// فقط الحقول التي توجد مؤشراتها في الجدول tChampsVoulus
// هي المطلوبة. تبدأ الفهارس من 1
// إذا كان tChampsvoulus=null أو حجمه صفر، يتم أخذ جميع الحقول
// إذا كان strict=true، يجب أن تكون جميع الحقول المطلوبة موجودة
ستحتوي الفئة على السمة الخاصة التالية:
يتم تعيين هذا السمة بواسطة المنشئ السابق بالقيم التالية:
0: تمت عملية الإنشاء بنجاح
4: بعض الحقول المطلوبة غير موجودة في حين أن strict=true
وستحتوي الفئة أيضًا على طريقتين:
التي تعرض قيمة السمة الخاصة erreur.
التي تعرض قيمة الكائن في شكل (خطأ، عنصر 1، عنصر 2، …) حيث العناصر i هي عناصر المتجه الذي تم إنشاؤه من السلسلة.
قد يكون برنامج الاختبار كما يلي:
import java.io.*;
//استيراد 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)
بعض النصائح:
- لتقسيم السلسلة S إلى حقول، استخدم الطريقة split من الفئة String.
- ضع حقول S في قاموس D مفهرس برقم الحقل
- استرجع من القاموس D الحقول التي تحتوي على مفتاحها (فهرسها) في الجدول tChampsVoulus.
4.12.3. التمرين 3
نرغب في إضافة المنشئ التالي إلى الفئة stringtovector:
public stringtovector(String S, String separateur, String sChampsVoulus,boolean strict){
// يُنشئ متجهًا باستخدام حقول السلسلة S
// تتكون هذه السلسلة من حقول مفصولة بفاصل
// إذا كان الفاصل=null، فإن السلسلة تشكل حقلًا واحدًا فقط
// فقط الحقول التي توجد مؤشراتها في sChampsVoulus هي المطلوبة
// تبدأ الفهارس من 1
// إذا كان sChampsvoulus=null أو ""، يتم أخذ جميع الحقول
// إذا كان strict=true، يجب أن تكون جميع الحقول المطلوبة موجودة
وبالتالي، فإن قائمة الحقول المطلوبة موجودة في سلسلة (String) بدلاً من مصفوفة من الأعداد الصحيحة (int[]). يمكن تعيين قيمة جديدة للسمة الخاصة erreur للفئة:
2: سلسلة مؤشرات الحقول المطلوبة غير صحيحة
فيما يلي برنامج نموذجي:
import java.io.*;
//استيراد 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)
بعض النصائح:
- يجب الرجوع إلى حالة الباني السابق عن طريق نقل حقول السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة. للقيام بذلك، قم بتقسيم sChampsVoulus إلى حقول باستخدام كائن StringTokenizer الذي سيعطي السمة countTokens عدد الحقول التي تم الحصول عليها. يمكن بعد ذلك إنشاء مصفوفة من الأعداد الصحيحة بالحجم المناسب وملؤها بالحقول التي تم الحصول عليها.
- لمعرفة ما إذا كان الحقل عددًا صحيحًا، استخدم الطريقة Integer.parseInt لتحويل الحقل إلى عدد صحيح ومعالجة الاستثناء الذي سيتم إنشاؤه عندما يتعذر إجراء هذا التحويل.
4.12.4. التمرين 4
نرغب في إنشاء فئة filetovector تسمح بنقل محتوى ملف نصي إلى كائن Vector. ستكون هذه الفئة مشتقة من الفئة Vector:
وستحتوي على المنشئ التالي:
// --------------------- منشئ
public filetovector(String nomFichier, String separateur, int [] tChampsVoulus,boolean strict, String tagCommentaire){
// ينشئ متجهًا باستخدام أسطر ملف النص nomFichier
// تتكون الأسطر من حقول مفصولة بفاصل
// إذا كان الفاصل=null، فإن السطر يشكل حقلًا واحدًا فقط
// فقط الحقول التي توجد مؤشراتها في tChampsVoulus هي المطلوبة
// تبدأ الفهارس من 1
// إذا كان tChampsvoulus=null أو فارغًا، يتم أخذ جميع الحقول
// إذا كان strict=true، يجب أن تكون جميع الحقول المطلوبة موجودة
// إذا لم يكن الأمر كذلك، لا يتم حفظ السطر ويتم وضع مؤشره
// يتم وضعه في المتجه lignesErronees
// يتم تجاهل الأسطر الفارغة
// وكذلك الأسطر التي تبدأ بـ tagCommentaire إذا كان tagCommentaire != null
ستحتوي الفئة على السمات الخاصة التالية:
يتم تعيين السمة erreur بواسطة المنشئ السابق بالقيم التالية:
0: تمت عملية الإنشاء بنجاح
1: تعذر فتح الملف المطلوب
4: بعض الحقول المطلوبة غير موجودة في حين أن strict=true
8: حدث خطأ في الإدخال/الإخراج أثناء معالجة الملف
السمة lignesErronees هي متجه تتكون عناصره من أرقام الأسطر الخاطئة في شكل سلسلة أحرف. تعتبر السطر خاطئة إذا لم تتمكن من توفير الحقول المطلوبة في حين أن strict=true.
ستحتوي الفئة أيضًا على طريقتين:
الذي يعرض قيمة السمة الخاصة erreur.
الذي يعرض قيمة الكائن بالشكل (خطأ، العنصر 1، العنصر 2 …، (l1، l2، …)) حيث العناصر i هي عناصر المتجه الذي تم إنشاؤه من الملف و li هي أرقام الأسطر التي تحتوي على أخطاء.
فيما يلي مثال للاختبار:
import java.io.*;
//استيراد 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,# تعليق) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# تعليق) (0,azerty,1,cvf,fff,qqqq) (0,s)]
بعض النصائح
-
يتم معالجة الملف النصي سطراً سطراً. يتم تقسيم السطر إلى حقول بفضل فئة stringtovector التي تمت دراستها سابقاً.
-
وبالتالي، فإن عناصر المتجه المكون من الملف النصي هي كائنات من نوع stringtovector.
-
يمكن أن تعتمد طريقة identite الخاصة بـ filetovector على الطريقة stringtovector.identite() لعرض عناصرها، وكذلك على الطريقة Vector.toString() لعرض أرقام الأسطر التي تحتوي على أخطاء.
4.12.5. التمرين 5
نرغب في إضافة المنشئ التالي إلى فئة filetovector:
public filetovector(String nomFichier, String separateur, String sChampsVoulus,
boolean strict, String tagCommentaire){
// ينشئ متجهًا باستخدام الأسطر الموجودة في ملف نصي nomFichier
// تتكون الأسطر من حقول مفصولة بفاصل
// إذا كان الفاصل=null، فإن السطر يشكل حقلًا واحدًا فقط
// فقط الحقول التي توجد مؤشراتها في tChampsVoulus هي المطلوبة
// تبدأ الفهارس بـ 1
// إذا كان sChampsvoulus=null أو فارغًا، يتم أخذ جميع الحقول
// إذا كان strict=صحيح، يجب أن تكون جميع الحقول المطلوبة موجودة
// إذا لم يكن الأمر كذلك، لا يتم حفظ السطر ويتم وضع مؤشره
// يتم وضعه في المتجه lignesErronees
// يتم تجاهل الأسطر الفارغة
// وكذلك الأسطر التي تبدأ بـ tagCommentaire إذا كان tagCommentaire != null
أصبحت قائمة فهارس الحقول المطلوبة الآن في سلسلة أحرف (String) بدلاً من أن تكون في مصفوفة من الأعداد الصحيحة.
يمكن أن يكون للسمة الخاصة erreur قيمة إضافية:
2: سلسلة مؤشرات الحقول المطلوبة غير صحيحة
فيما يلي مثال على الاختبار:
import java.io.*;
//استيراد 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,# تعليق) (0,azerty,1,cvf,fff,qqqq) (0,s)]
[0,(0,a,b,c,d,e) (0,1,2,3,4,5) (0,# تعليق) (0,azerty,1,cvf,fff,qqqq) (0,s)]
بعض النصائح
- سنحول السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة tChampVoulus لنعود إلى حالة المنشئ السابق.