4. الفئات الشائعة الاستخدام في Java
في هذا الفصل، نقدم عددًا من فئات Java الشائعة الاستخدام. تحتوي هذه الفئات على العديد من السمات والطرق والمُنشِئات. في كل حالة، نقدم جزءًا صغيرًا فقط من الفئات. تتوفر تفاصيل حول هذه الفئات في تعليمات Java، التي نقدمها الآن.
4.1. الوثائق
إذا كنت قد قمت بتثبيت Sun JDK في المجلد <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. فئات الاختبار
تستخدم الأمثلة التالية أحيانًا فئتي 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> = "<bdi dir="ltr" class="odt-ltr-term">horse</bdi>"** أو **<bdi dir="ltr" class="odt-ltr-term">name</bdi> = <bdi dir="ltr" class="odt-ltr-term">new String</bdi>("<bdi dir="ltr" class="odt-ltr-term">horse</bdi>")**
كلا الطريقتين متكافئتان. إذا كتبنا لاحقًا name="fish"، فإن name تشير عندئذٍ إلى كائن جديد. ويُفقد الكائن القديم String("horse")، ويتم استرداد الذاكرة التي كان يشغلها.
تحتوي فئة 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 هي واجهة تحدد طريقة واحدة فقط:
والتي يجب أن ترجع 0 إذا كان o1=o2، -1: إذا كان o1 < o2، +1: إذا كان o1 > o2. في النموذج الأولي void sort(Object[] obj, Comparator C)، يجب أن تكون الحجة الثانية C كائنًا ينفذ واجهة Comparator. في منشئ sort2، اخترنا الكائن الحالي this:
وهذا يتطلب منا القيام بأمرين:
- الإشارة إلى أن فئة sort2 تنفذ واجهة Comparator
- كتابة دالة المقارنة في فئة 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، نستخدم العمر هنا (كان بإمكاننا استخدام الاسم).
فيما يلي نتائج التنفيذ:
كان بإمكاننا اتباع نهج مختلف لتنفيذ واجهة 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. لذلك، يصبح إعلانها كما يلي:
الآن نختبر طريقة 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:
تستقبل طريقة البحث جميع المعلمات التي تحتاجها لاستدعاء طريقة 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
الملف الناتج الذي أنشأه البرنامج هو كما يلي:
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
يؤدي تشغيل البرنامج إلى النتائج التالية:
4.9.3. حفظ كائن شخص
نطبق ما رأيناه للتو لتزويد فئة Person بطريقة تسمح لنا بحفظ سمات الشخص في ملف. نضيف الطريقة saveAttributes إلى تعريف فئة Person:
// ------------------------------
// sauvegarde dans fichier texte
// ------------------------------
public void sauveAttributs(PrintWriter P){
P.println(""+this);
}
قبل تعريف فئة Person، لا تنسَ استيراد حزمة 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" مع حرفين متتاليين متطابقين. |
|
قد يظهر عنصر في نمط مرة واحدة أو عدة مرات. دعونا نلقي نظرة على بعض الأمثلة التي تتضمن الرمز \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 بالتحقق مما إذا كانت سلسلة تتطابق مع نمط معين. للقيام بذلك، استخدم الطريقة الثابتة
مع: 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
ونتيجة التنفيذ:
لاحظ أنه في النمط "^\s*\d+\s*$"، يجب مضاعفة الحرف \ بسبب تفسير Java الخاص لهذا الحرف. لذلك نكتب: String pattern1="^\\s*\\d+\\s*$";
4.11.3. البحث عن جميع عناصر السلسلة التي تتطابق مع نمط
لنأخذ النمط "\d+" والسلسلة " 123 456 789 " كمثال. يوجد النمط في ثلاثة أماكن مختلفة في السلسلة. تتيح لك فئتا Pattern و Matcher استرداد المرات المختلفة لظهور نمط ما في سلسلة. فئة Pattern هي الفئة التي تتعامل مع التعبيرات العادية. يجب "تجميع" التعبير العادي المستخدم أكثر من مرة. يؤدي ذلك إلى تسريع عمليات البحث عن الأنماط في السلاسل. تقوم طريقة التجميع الثابتة (static compile) بهذه المهمة:
تأخذ سلسلة النمط كمعلمة وتُرجع كائن Pattern. لمقارنة نمط كائن Pattern بسلسلة، نستخدم فئة Matcher. تسمح هذه الفئة بمقارنة نمط بسلسلة. من كائن Pattern، يمكن الحصول على كائن Matcher باستخدام طريقة matcher:
input هي السلسلة التي سيتم مقارنتها بالنمط.
لذلك، لمقارنة النمط "\d+" بالسلسلة " 123 456 789 "، يمكنك إنشاء كائن Matcher كما يلي:
باستخدام كائن النتائج المذكور أعلاه، يمكننا استرداد المرات المختلفة لظهور النمط في السلسلة. للقيام بذلك، نستخدم الطرق التالية لفئة 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.*;
// 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)
ستحتوي فئة الخيارات على الواجهة التالية (مُستردات):
تُرجع مرجعًا إلى مصفوفة optionsValides التي تم إنشاؤها عند إنشاء كائن الخيارات
تُرجع مرجعًا إلى مصفوفة invalidOptions التي تم إنشاؤها عند إنشاء كائن الخيارات
تُرجع مرجعًا إلى سلسلة optionsWithout التي تم إنشاؤها عند إنشاء كائن options
تُرجع قيمة سمة error التي تم إنشاؤها عند إنشاء كائن options
في حالة عدم وجود أخطاء، تعرض قيم سمات 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:
وستحتوي على المنشئ التالي:
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
ستحتوي الفئة على السمة الخاصة التالية:
يتم تعيين هذه السمة بواسطة المنشئ السابق بالقيم التالية:
0: تم الإنشاء بنجاح
4: بعض الحقول المطلوبة مفقودة على الرغم من أن strict=true
وستحتوي الفئة أيضًا على طريقتين:
التي تُرجع قيمة السمة الخاصة error.
الذي يعرض قيمة الكائن في الصيغة (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)
بعض النصائح:
- لتقسيم السلسلة S إلى حقول، استخدم طريقة split الخاصة بفئة String.
- ضع حقول S في قاموس D مفهرس برقم الحقل
- استرجع من القاموس 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)
بعض النصائح:
- تحتاج إلى العودة إلى حالة المنشئ السابق عن طريق نقل الحقول من السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة. للقيام بذلك، قم بتقسيم sChampsVoulus إلى حقول باستخدام كائن StringTokenizer، حيث ستعطي سمة countTokens عدد الحقول التي تم الحصول عليها. يمكنك بعد ذلك إنشاء مصفوفة من الأعداد الصحيحة بالحجم الصحيح وملؤها بالحقول التي تم الحصول عليها.
- لتحديد ما إذا كان الحقل عددًا صحيحًا، استخدم طريقة Integer.parseInt لتحويل الحقل إلى عدد صحيح والتعامل مع الاستثناء الذي سيتم طرحه إذا كان هذا التحويل غير ممكن.
4.12.4. التمرين 4
نريد إنشاء فئة filetovector تسمح لنا بنقل محتويات ملف نصي إلى كائن Vector. ستُشتق هذه الفئة من فئة 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
ستحتوي الفئة على السمات الخاصة التالية:
يتم تعيين السمة error بواسطة المنشئ السابق بالقيم التالية:
0: تمت عملية الإنشاء بنجاح
1: تعذر فتح الملف المراد معالجته
4: بعض الحقول المطلوبة مفقودة على الرغم من أن strict=true
8: حدث خطأ في الإدخال/الإخراج أثناء معالجة الملف
السمة lignesErronees هي متجه تتكون عناصره من أرقام الأسطر الخاطئة في شكل سلاسل أحرف. ويُعتبر السطر خاطئًا إذا لم يتمكن من توفير الحقول المطلوبة عندما تكون قيمة strict=true.
وستحتوي الفئة أيضًا على طريقتين:
التي تُرجع قيمة السمة الخاصة error.
الذي يعرض قيمة الكائن في الصيغة (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)]
بعض النصائح
-
تتم معالجة الملف النصي سطراً سطراً. يتم تقسيم السطر إلى حقول باستخدام فئة 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){
// 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)]
- سنقوم بتحويل السلسلة sChampsVoulus إلى مصفوفة من الأعداد الصحيحة tChampVoulus لإعادتها إلى حالة المنشئ السابق.