4. إدارة الأخطاء
في البرمجة، هناك قاعدة مطلقة: يجب ألا «يتعطل» البرنامج أبدًا بشكل مفاجئ. يجب معالجة جميع الأخطاء التي قد تحدث أثناء تنفيذ البرنامج، كما يجب إنشاء رسائل خطأ ذات مغزى.
إذا عدنا إلى مثال الضرائب الذي تناولناه سابقًا، فماذا يحدث إذا أدخل المستخدم أي قيمة عشوائية لعدد الأطفال؟ لنلقِ نظرة على هذا المثال:
هذا ما يُسمى «تعطل» غير متوقع. حدث «تعطل» في الأمر children=cint(wscript.arguments(1)) لأن arguments(1) احتوى على السلسلة «xyzt».
قبل استخدام متغير لا نعرف طبيعته بالضبط، يجب التحقق من نوعه الفرعي الدقيق. يمكن القيام بذلك بعدة طرق:
- اختبار النوع الفعلي للبيانات الموجودة في متغير باستخدام الدالتين vartype أو typename
- استخدام تعبير منتظم للتحقق من أن محتوى المتغير يتطابق مع نموذج معين
- السماح بحدوث الخطأ ثم اعتراضه ومعالجته
سنستعرض هذه الطرق المختلفة.
4.1. معرفة النوع الدقيق للبيانات
تجدر الإشارة إلى أن الدالتين vartype أو varname تسمحان بمعرفة النوع الدقيق للبيانات. لكن هذا لا يساعدنا دائمًا بشكل كبير. على سبيل المثال، عندما نقرأ بيانات تم إدخالها عبر لوحة المفاتيح، ستخبرنا الدالتان vartype و typename أنها سلسلة أحرف، لأن هذه هي الطريقة التي تُعتبر بها أي بيانات يتم إدخالها عبر لوحة المفاتيح. وهذا لا يخبرنا ما إذا كان يمكن اعتبار هذه السلسلة، على سبيل المثال، رقمًا صالحًا. لذلك نستخدم دوال أخرى للوصول إلى هذا النوع من المعلومات:
isNumeric(expression) | تُرجع القيمة «صحيح» إذا كان التعبير يمكن استخدامه كرقم |
isDate(expression) | تُرجع القيمة «صحيح» إذا كان التعبير يمكن استخدامه كتاريخ |
isEmpty(var) | تُرجع القيمة «صحيح» إذا لم يتم تهيئة المتغير var |
isNull(var) | تُرجع القيمة "صحيح" إذا كانت المتغير var تحتوي على بيانات غير صالحة |
isArray(var) | تُرجع القيمة "صحيح" إذا كانت var عبارة عن مصفوفة |
isObject(var) | تُرجع القيمة "صحيح" إذا كان var كائنًا |
يطلب المثال التالي إدخال بيانات من لوحة المفاتيح حتى يتم التعرف عليها كرقم:
البرنامج
' قراءة البيانات حتى يتم التعرف عليها كرقم
Option Explicit
Dim fini, nombre
' يتم تكرار العملية ما دامت البيانات المدخلة غير صحيحة
' يتم التحكم في الحلقة بواسطة متغير منطقي محدود، يتم تعيينه على «خطأ» في البداية (= لم تنتهِ العملية بعد)
fini=false
Do While Not fini
' يُطلب إدخال الرقم
wscript.stdout.write "Tapez un nombre : "
' يتم قراءته
nombre=wscript.stdin.readLine
' يكون النوع بالضرورة «سلسلة» عند القراءة
wscript.echo "Type de la donnée lue : " & typename(nombre) & "," & vartype(nombre)
' يتم اختبار النوع الفعلي للبيانات التي تمت قراءتها
If isNumeric(nombre) Then
fini=true
Else
wscript.echo "Erreur, vous n'avez pas tapé un nombre. Recommencez svp..."
End If
Loop
' تأكيد
wscript.echo "Merci pour le nombre " & nombre
' ونهاية
wscript.quit 0
النتائج
لا تخبرنا الدالة isNumeric ما إذا كان التعبير عددًا صحيحًا أم لا. للحصول على هذه المعلومة، يجب إجراء اختبارات إضافية. يطلب المثال التالي عددًا صحيحًا أكبر من 0:
البرنامج
' قراءة البيانات حتى يتم التعرف عليها كعدد صحيح >0
Option Explicit
Dim fini, nombre
' يتم تكرار الحلقة ما دامت البيانات المدخلة غير صحيحة
' يتم التحكم في الحلقة بواسطة متغير منطقي محدود، يتم تعيينه على «خطأ» في البداية (= لم تنتهِ بعد)
fini=false
Do While Not fini
' يُطلب إدخال الرقم
wscript.stdout.write "Tapez un nombre entier >0: "
' يتم قراءته
nombre=wscript.stdin.readLine
' يتم اختبار النوع الحقيقي للبيانات التي تمت قراءتها
If isNumeric(nombre) Then
' هل هو عدد صحيح (رقم يساوي الجزء الصحيح منه) موجب؟
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' رسالة خطأ محتملة
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' تأكيد
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' ونهاية
wscript.quit 0
النتائج
تعليقات:
- int(nombre) يعطي الجزء الصحيح من عدد ما. والعدد الذي يساوي الجزء الصحيح منه هو عدد صحيح.
- ومن المثير للاهتمام ملاحظة أنه كان لا بد من استخدام الاختبار If (العدد - int(العدد)) = 0 And العدد > 0 لأن الاختبار If العدد = int(العدد) And العدد > 0 لم يعطِ النتائج المتوقعة. فهو لم يكتشف الأعداد الصحيحة الموجبة. ونترك للقارئ مهمة اكتشاف السبب.
- اختبار If (العدد - int(العدد)) = 0 ليس موثوقًا تمامًا. لنلقِ نظرة على مثال التنفيذ التالي:
لا يتم تمثيل الأعداد الحقيقية بدقة، بل بشكل تقريبي. وفي هذه الحالة، أسفرت العملية nombre-int(nombre) عن النتيجة 0 وفقًا لدقة الحاسوب.
4.2. التعبيرات النمطية
تسمح لنا التعبيرات النمطية بفحص تنسيق سلسلة أحرف. وبذلك يمكننا التحقق من أن السلسلة التي تمثل تاريخًا تكون بالتنسيق jj/mm/aa. وللقيام بذلك، نستخدم نموذجًا ونقارن السلسلة بهذا النموذج. وفي هذا المثال، يجب أن تكون j و m و a أرقامًا. ونموذج تنسيق التاريخ الصحيح هو «\d\d/\d\d/\d\d»، حيث يشير الرمز \d إلى رقم. الرموز التي يمكن استخدامها في النموذج هي التالية (وثائق مايكروسوفت):
الحرف | الوصف |
\ | يُشير إلى الحرف التالي على أنه حرف خاص أو حرف حرفي. على سبيل المثال، "n" يمثل الحرف "n". و"\n" يمثل حرف السطر الجديد. التسلسل "\\" يمثل "\"، بينما "\(" يمثل "(". |
^ | يشير إلى بداية الإدخال. |
$ | يمثل نهاية الإدخال. |
* | يمثل الحرف السابق صفر مرة أو عدة مرات. وبالتالي، فإن "zo*" يمثل "z" أو "zoo". |
+ | يستبدل الحرف السابق مرة واحدة أو أكثر. وبالتالي، فإن "zo+" يستبدل "zoo"، ولكنه لا يستبدل "z". |
? | يتطابق مع الحرف السابق صفر مرة أو مرة واحدة. على سبيل المثال، "a?ve?" يتطابق مع "ve" في كلمة "lever". |
. | يتطابق مع أي حرف فردي، باستثناء حرف السطر الجديد. |
(نموذج) | يبحث عن modèle ويحفظ المطابقة. يمكن استخراج السلسلة الفرعية المطابقة من مجموعة «Matches» التي تم الحصول عليها، باستخدام العنصر [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" مع حرفين متطابقين متتاليين. |
\n | يعادل n، حيث n هو قيمة هروب ثمانية. يجب أن تتألف قيم الهروب الثمانية من 1 أو 2 أو 3 أرقام. على سبيل المثال، "\11" و "\011" كلاهما يعادل حرف الجدولة. "\0011" تعادل "\001" و"1". يجب ألا تتجاوز قيم الهروب الثمانية 256. إذا تجاوزت هذا الحد، فلن يؤخذ في الاعتبار سوى أول رقمين في التعبير. تسمح باستخدام الرموز ASCII في التعبيرات النمطية. |
\xn | تتوافق مع n، حيث n هي قيمة هروب سداسية عشرية. يجب أن تتكون قيم الهروب السداسية العشرية من رقمين على الأقل. على سبيل المثال، "\x41" تعني "A". و"\x041" تعادل "\x04" و"1". يسمح باستخدام الرموز ASCII في التعبيرات النمطية. |
يمكن أن يظهر عنصر ما في القالب مرة واحدة أو عدة مرات. لنأخذ بعض الأمثلة حول الرمز \d الذي يمثل رقمًا واحدًا:
القالب | المعنى |
\d | رقم واحد |
\d? | رقم واحد أو صفر |
\d* | رقم واحد أو أكثر |
\d+ | رقم واحد أو أكثر |
\d{2} | رقمان |
\d{3,} | 3 أرقام على الأقل |
\d{5,7} | ما بين 5 و7 أرقام |
لنتخيل الآن النموذج القادر على وصف التنسيق المتوقع لسلسلة أحرف:
السلسلة المطلوبة | النموذج |
تاريخ بتنسيق يي/ش/س | \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 |
يمكن «استخراج» المجموعات الفرعية لنموذج ما. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نموذج معين، بل يمكننا أيضًا استخراج العناصر من هذه السلسلة التي تتطابق مع المجموعات الفرعية للنموذج والتي تم وضعها بين أقواس. فإذا قمنا بتحليل سلسلة تحتوي على تاريخ بالصيغة يي/شش/سس، وأردنا أيضًا استخراج العناصر يي، شش، سس من هذا التاريخ، فسنستخدم النموذج (\d\d)/(\d\d)/(\d\d).
لنرى في هذا المثال كيف يتم العمل باستخدام VBScript.
- علينا أولاً إنشاء كائن RegExp (التعبير العادي)
- ثم نحدد النمط المراد اختباره
- قد نرغب في عدم التمييز بين الأحرف الكبيرة والصغيرة (يتم التمييز بشكل افتراضي). هنا لا يهم ذلك على الإطلاق.
- قد ترغب في البحث عن النمط عدة مرات في السلسلة (بشكل افتراضي، لا يتم ذلك)
لا يكون البحث الشامل ذا معنى إلا إذا كان النمط المستخدم لا يشير إلى بداية السلسلة أو نهايتها.
- لذلك نبحث عن جميع المطابقات للنموذج في السلسلة:
تُرجع الطريقة execute الخاصة بالكائن RegExp مجموعة من الكائنات من النوع match. يحتوي هذا الكائن على خاصية value تمثل العنصر في chaine المطابق للنموذج. إذا تمت كتابة modele.global=true، فقد يكون هناك عدة مطابقات. ولهذا السبب، فإن نتيجة الطريقة execute هي مجموعة من المطابقات.
- يُحدد عدد المطابقات بواسطة correspondances.count. إذا كان هذا العدد يساوي 0، فهذا يعني أن النموذج لم يتم العثور عليه في أي مكان. يتم تحديد قيمة المطابقة رقم i بواسطة correspondances(i).value. إذا كان النموذج يحتوي على نماذج فرعية بين قوسين، فإن العناصر في correspondances(i) المطابقة للقوس j في النموذج هي correspondances(i).submatches(j).
يتم توضيح كل هذا في المثال التالي:
البرنامج
' التعبير النمطي
' نريد التحقق من أن السلسلة تحتوي على تاريخ بتنسيق يوم/شهر/سنة
Option Explicit
Dim modele
' نحدد النموذج
Set modele=new regexp
modele.pattern="\b(\d\d)/(\d\d)/(\d\d)\b" ' une date n'importe où dans la chaîne
modele.global=true ' on recherchera le modèle plusieurs fois dans la chaîne
' المستخدم هو الذي يقدم السلسلة التي سيتم البحث فيها عن النموذج
Dim chaine, correspondances, i
chaine=""
' نقوم بالتكرار طالما أن السلسلة <> "النهاية"
Do While true
' يُطلب من المستخدم إدخال نص
wscript.stdout.writeLine "Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrêter : "
chaine=wscript.stdin.readLine
' تنتهي العملية إذا كانت السلسلة = "fin"
If chaine="fin" Then Exit Do
' نقوم بمقارنة السلسلة التي تمت قراءتها بنموذج التاريخ
Set correspondances=modele.execute(chaine)
' هل تم العثور على تطابق
If correspondances.count<>0 Then
' هناك تطابق واحد على الأقل
For i=0 To correspondances.count-1
' يتم عرض المطابقة i
wscript.echo "J'ai trouvé la date " & correspondances(i).value
' يتم استرداد العناصر الفرعية للتطابق i
wscript.echo "Les éléments de la date " & i & " sont (" & correspondances(i).submatches(0) & "," _
& correspondances(i).submatches(1) & "," & correspondances(i).submatches(2) & ")"
Next
Else
' لا توجد مطابقة
wscript.echo "Je n'ai pas trouvé de date au format jj/mm/aa dans votre texte"
End If
Loop
' انتهى
wscript.quit 0
النتائج
باستخدام التعبيرات النمطية، يمكن كتابة البرنامج الذي يتحقق من أن الإدخال من لوحة المفاتيح هو عدد صحيح موجب على النحو التالي:
البرنامج
' قراءة البيانات حتى يتم التعرف عليها كرقم
Option Explicit
Dim fini, nombre
' يتم تعريف نموذج عدد صحيح موجب (ولكنه قد يكون صفرًا)
Dim modele
Set modele=new regexp
modele.pattern="^\s*\d+\s*$"
' يتم تكرار العملية ما دامت البيانات المدخلة غير صحيحة
' يتم التحكم في الحلقة بواسطة متغير منطقي محدود، يتم تعيينه على «خطأ» في البداية (= لم تنتهِ العملية بعد)
fini=false
Do While Not fini
' يُطلب إدخال الرقم
wscript.stdout.write "Tapez un nombre entier >0: "
' يتم قراءة الرقم
nombre=wscript.stdin.readLine
' يتم فحص تنسيق البيانات التي تمت قراءتها
Dim correspondances
Set correspondances=modele.execute(nombre)
' هل تم التحقق من النموذج؟
If correspondances.count<>0 Then
' إنه عدد صحيح، لكن هل هو أكبر من 0؟
nombre=cint(nombre)
If nombre>0 Then
fini=true
End If
End If
' رسالة خطأ محتملة
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' تأكيد
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' ونهاية
wscript.quit 0
النتائج
قد يمثل العثور على التعبير النمطي الذي يسمح لنا بالتحقق من أن سلسلة ما تتطابق بالفعل مع نموذج معين تحديًا حقيقيًا في بعض الأحيان. يتيح البرنامج التالي التدرب على ذلك. فهو يطلب نموذجًا وسلسلة، ثم يشير إلى ما إذا كانت السلسلة تتطابق مع النموذج أم لا.
البرنامج
' تعبير منتظم
' نريد التحقق من أن سلسلة ما تتطابق مع نموذج
Option Explicit
' نحدد النموذج
Dim modele
Set modele=new regexp
modele.global=true ' on recherchera le modèle plusieurs fois dans la chaîne
' المستخدم هو الذي يقدم السلسلة التي سيتم البحث فيها عن النمط
Dim chaine, correspondances, i
Do While true
' يُطلب من المستخدم إدخال نمط
wscript.stdout.write "Tapez le modèle à tester et fin pour arrêter : "
modele.pattern=wscript.stdin.readLine
' هل انتهيت؟
If modele.pattern="fin" Then Exit Do
' يُطلب من المستخدم إدخال السلاسل المراد مقارنتها بالنموذج
Do While true
' يُطلب من المستخدم إدخال نموذج
wscript.stdout.writeLine "Tapez la chaîne à tester avec le modèle [" & modele.pattern & "] et fin pour arrêter : "
chaine=wscript.stdin.readLine
' انتهى؟
If chaine="fin" Then Exit Do
' يتم مقارنة السلسلة التي تمت قراءتها بنموذج التاريخ
Set correspondances=modele.execute(chaine)
' هل تم العثور على تطابق؟
If correspondances.count<>0 Then
' هناك تطابق واحد على الأقل
For i=0 To correspondances.count-1
' يتم عرض المطابقة i
wscript.echo "J'ai trouvé la correspondance " & correspondances(i).value
Next
Else
' لا توجد مطابقة
wscript.echo "Je n'ai pas trouvé de correspondance"
End If
Loop
Loop
' انتهى
wscript.quit 0
النتائج
4.3. التعامل مع أخطاء التنفيذ
هناك طريقة أخرى لإدارة أخطاء التنفيذ تتمثل في السماح بحدوثها، ثم تلقي إشعار بها ومعالجتها في ذلك الوقت. عادةً، عندما يحدث خطأ أثناء التنفيذ، يعرض WSH رسالة خطأ ويتم إيقاف البرنامج. هناك تعليمتان تسمحان لنا بتعديل طريقة العمل هذه:
يُعلم هذا الأمر النظام (WSH) بأننا سنقوم بمعالجة الأخطاء بأنفسنا. بعد هذا الأمر، يتم تجاهل أي خطأ ببساطة من قبل النظام.
تعيدنا هذه التعليمات إلى طريقة العمل العادية لإدارة الأخطاء.
عندما تكون التعليمات on error resume next نشطة، يتعين علينا إدارة الأخطاء التي قد تحدث بأنفسنا. يساعدنا الكائن Err في ذلك. يحتوي هذا الكائن على خصائص وأساليب متنوعة، وسنركز على التاليتين:
- number: عدد صحيح يمثل رقم آخر خطأ حدث. 0 تعني "لا يوجد خطأ"
- description: رسالة الخطأ التي كان سيُعرضها النظام لو لم يتم إصدار الأمر on error resume next
لنلقِ نظرة على المثال التالي:
البرنامج
' خطأ غير معالج
Option Explicit
Dim nombre
nombre=cdbl("abcd")
wscript.echo "nombre=" & nombre
النتائج
لنعالج الخطأ الآن:
البرنامج
' خطأ تمت معالجته
Option Explicit
Dim nombre
' نقوم بمعالجة الأخطاء بأنفسنا
On Error Resume Next
nombre=cdbl("abcd")
' هل حدث خطأ؟
If Err.number<>0 Then
wscript.echo "L'erreur [" & err.description & "] s'est produite"
On Error GoTo 0
wscript.quit 1
End If
' لا توجد أخطاء - نعود إلى التشغيل العادي
On Error GoTo 0
wscript.echo "nombre=" & nombre
wscript.quit 0
النتائج
لنعد كتابة برنامج إدخال عدد صحيح >0 باستخدام هذه الطريقة الجديدة:
البرنامج
' قراءة البيانات حتى يتم التعرف عليها كرقم
Option Explicit
Dim fini, nombre
' يتم تكرار الحلقة حتى تصبح البيانات المدخلة صحيحة
' يتم التحكم في الحلقة بواسطة متغير منطقي محدود، يتم تعيينه على «خطأ» في البداية (= لم تنتهِ العملية بعد)
fini=false
Do While Not fini
' يُطلب إدخال الرقم
wscript.stdout.write "Tapez un nombre entier >0: "
' يتم قراءة الرقم
nombre=wscript.stdin.readLine
' يتم فحص تنسيق البيانات التي تمت قراءتها
On Error Resume Next
nombre=cdbl(nombre)
If err.number=0 Then
' لا توجد أخطاء، إنه رقم
' نعود إلى الوضع العادي لإدارة الأخطاء
On Error GoTo 0
' هل هو عدد صحيح أكبر من 0
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' العودة إلى الوضع العادي لإدارة الأخطاء
On Error GoTo 0
' رسالة خطأ محتملة
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' تأكيد
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' ونهاية
wscript.quit 0
النتائج
Tapez un nombre entier >0: 4.5
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: 4,5
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: abcd
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: -4
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: 1
Merci pour le nombre entier >0 : 1
تعليقات:
- تكون هذه الطريقة أحيانًا هي الطريقة الوحيدة القابلة للاستخدام. لذا يجب ألا تنسَ العودة إلى الوضع العادي لإدارة الأخطاء بمجرد انتهاء تسلسل التعليمات الذي قد يتسبب في حدوث الخطأ.
4.4. التطبيق على برنامج حساب الضرائب
نستعيد برنامج حساب الضرائب الذي تمت كتابته مسبقًا، لنقوم هذه المرة بالتحقق من صحة المعلمات التي تم تمريرها إلى البرنامج:
البرنامج
' حساب ضريبة أحد المكلفين
' يجب استدعاء البرنامج بثلاثة معلمات: متزوج، أطفال، راتب
' متزوج: الحرف O إذا كان متزوجًا، وN إذا كان غير متزوج
' الأطفال: عدد الأطفال
' الراتب: الراتب السنوي بدون السنتات
' لا يتم إجراء أي تحقق من صحة البيانات، ولكن
' يتم التحقق من وجود ثلاثة أطفال بالفعل
' الإعلان الإلزامي عن المتغيرات
Option Explicit
Dim syntaxe
syntaxe= _
"Syntaxe : pg marié enfants salaire" & vbCRLF & _
"marié : caractère O si marié, N si non marié" & vbCRLF & _
"enfants : nombre d'enfants (entier >=0)" & vbCRLF & _
"salaire : salaire annuel sans les centimes (entier >=0)"
' يتم التحقق من وجود 3 معلمات
Dim nbArguments
nbArguments=wscript.arguments.count
If nbArguments<>3 Then
' رسالة خطأ
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect"
' التوقف مع رمز الخطأ 1
wscript.quit 1
End If
' استرداد المعلمات مع التحقق من صحتها
' يتم تمرير وسيطة إلى البرنامج دون مسافات أمامها أو خلفها
' سيتم استخدام التعبيرات النمطية للتحقق من صحة البيانات
Dim modele, correspondances
Set modele=new regexp
' يجب أن تكون الحالة الاجتماعية ضمن الأحرف المسموح بها oOnN
modele.pattern="^[oOnN]$"
Set correspondances=modele.execute(wscript.arguments(0))
If correspondances.count=0 Then
' خطأ
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect"
' نخرج
wscript.quit 2
End If
' يتم استرداد القيمة
Dim marie
If lcase(wscript.arguments(0)) = "o"Then
marie=true
Else
marie=false
End If
' يجب أن يكون عدد الأطفال عددًا صحيحًا >=0
modele.pattern="^\d{1,2}$"
Set correspondances=modele.execute(wscript.arguments(1))
If correspondances.count=0 Then
' خطأ
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect"
' الخروج
wscript.quit 3
End If
' استرداد القيمة
Dim enfants
enfants=cint(wscript.arguments(1))
' يجب أن يكون الراتب عددًا صحيحًا >=0
modele.pattern="^\d{1,9}$"
Set correspondances=modele.execute(wscript.arguments(2))
If correspondances.count=0 Then
' خطأ
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect"
' الخروج
wscript.quit 4
End If
' نسترد القيمة
Dim salaire
salaire=clng(wscript.arguments(2))
' يتم تحديد البيانات اللازمة لحساب الضريبة في 3 جداول
Dim limites, coeffn, coeffr
limites=array(12620,13190,15640,24740,31810,39970,48360, _
55790,92970,127860,151250,172040,195000,0)
coeffr=array(0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45, _
0.5,0.55,0.6,0.65)
coeffn=array(0,631,1290.5,2072.5,3309.5,4900,6898.5,9316.5, _
12106,16754.5,23147.5,30710,39312,49062)
' يتم حساب عدد الحصص
Dim nbParts
If marie=true Then
nbParts=(enfants/2)+2
Else
nbParts=(enfants/2)+1
End If
If enfants>=3 Then nbParts=nbParts+0.5
' نحسب الحصة العائلية والدخل الخاضع للضريبة
Dim revenu, qf
revenu=0.72*salaire
qf=revenu/nbParts
' يتم حساب الضريبة
Dim i, impot
i=0
Do While i<ubound(limites) And qf>limites(i)
i=i+1
Loop
impot=int(revenu*coeffr(i)-nbParts*coeffn(i))
' يتم عرض النتيجة
wscript.echo "impôt=" & impot
' الخروج دون أخطاء
wscript.quit 0
النتائج
C:\>cscript impots2.vbs
Syntaxe : pg marié enfants salaire
marié : caractère O si marié, N si non marié
enfants : nombre d'enfants (entier >=0)
salaire : salaire annuel sans les centimes (entier >=0)
erreur : nombre d'arguments incorrect
C:\>cscript impots2.vbs a b c
Syntaxe : pg marié enfants salaire
marié : caractère O si marié, N si non marié
enfants : nombre d'enfants (entier >=0)
salaire : salaire annuel sans les centimes (entier >=0)
erreur : argument marie incorrect
C:\>cscript impots2.vbs o b c
Syntaxe : pg marié enfants salaire
marié : caractère O si marié, N si non marié
enfants : nombre d'enfants (entier >=0)
salaire : salaire annuel sans les centimes (entier >=0)
erreur : argument enfants incorrect
C:\>cscript impots2.vbs o 2 c
Syntaxe : pg marié enfants salaire
marié : caractère O si marié, N si non marié
enfants : nombre d'enfants (entier >=0)
salaire : salaire annuel sans les centimes (entier >=0)
erreur : argument salaire incorrect
C:\>cscript impots2.vbs o 2 200000
impôt=22504