4. معالجة الأخطاء
في البرمجة، هناك قاعدة مطلقة واحدة: يجب ألا "يتعطل" البرنامج أبدًا بشكل غير متوقع. يجب معالجة جميع الأخطاء التي قد تحدث أثناء تنفيذ البرنامج، ويجب إنشاء رسائل خطأ ذات معنى.
إذا عدنا إلى مثال الضريبة الذي تمت مناقشته سابقًا، ماذا يحدث إذا أدخل المستخدم أي قيمة لعدد الأطفال؟ لنلقِ نظرة على هذا المثال:
هذا ما يُعرف بـ "التعطل المفاجئ". تسببت التعليمات enfants=cint(wscript.arguments(1)) في "تعطل" لأن arguments(1) احتوت على السلسلة "xyzt".
قبل استخدام متغير لا تُعرف طبيعته بالضبط، يجب عليك التحقق من نوعه الفرعي بالضبط. هناك عدة طرق للقيام بذلك:
- اختبار النوع الفعلي للبيانات الموجودة في متغير باستخدام دالتي vartype أو typename
- استخدام تعبير عادي للتحقق من أن محتوى المتغير يطابق نمطًا معينًا
- السماح بحدوث الخطأ، ثم اعتراضه ومعالجته
سنقوم بفحص هذه الطرق المختلفة.
4.1. تحديد النوع الدقيق لعنصر البيانات
تذكر أن دالتي vartype و varname تسمحان لك بتحديد النوع الدقيق لقطعة من البيانات. هذا ليس مفيدًا دائمًا. على سبيل المثال، عندما نقرأ البيانات المكتوبة على لوحة المفاتيح، ستخبرنا الدالتان vartype و typename أنها سلسلة، لأن جميع البيانات المكتوبة على لوحة المفاتيح تُعامل على هذا النحو. وهذا لا يخبرنا ما إذا كان يمكن، على سبيل المثال، اعتبار هذه السلسلة رقمًا صالحًا. لذلك نستخدم دوال أخرى للوصول إلى هذا النوع من المعلومات:
isNumeric(expression) | تُرجع القيمة true إذا كان التعبير يمكن استخدامه كرقم |
isDate(expression) | تُرجع القيمة true إذا كان التعبير يمكن استخدامه كتاريخ |
isEmpty(var) | تُرجع القيمة true إذا لم يتم تهيئة المتغير var |
isNull(var) | تُرجع القيمة true إذا كان المتغير var يحتوي على بيانات غير صالحة |
isArray(var) | تُرجع القيمة true إذا كان var عبارة عن مصفوفة |
isObject(var) | تُرجع القيمة true إذا كان var كائنًا |
يطلب المثال التالي من المستخدم إدخال البيانات عبر لوحة المفاتيح حتى يتم التعرف عليها كرقم:
البرنامج
' read data until it is recognized as a number
Option Explicit
Dim fini, nombre
' loop until the data entered is correct
' the loop is controlled by a finite boolean, set to false at the start (= it's not finite)
fini=false
Do While Not fini
' we ask for the number
wscript.stdout.write "Tapez un nombre : "
' we read it
nombre=wscript.stdin.readLine
' the type is necessarily string when read
wscript.echo "Type de la donnée lue : " & typename(nombre) & "," & vartype(nombre)
' test the actual type of data read
If isNumeric(nombre) Then
fini=true
Else
wscript.echo "Erreur, vous n'avez pas tapé un nombre. Recommencez svp..."
End If
Loop
' confirmation
wscript.echo "Merci pour le nombre " & nombre
' and end
wscript.quit 0
النتائج
لا تخبرنا الدالة isNumeric ما إذا كان التعبير عددًا صحيحًا أم لا. للحصول على هذه المعلومات، يلزم إجراء اختبارات إضافية. يطلب المثال التالي عددًا صحيحًا أكبر من 0:
البرنامج
' read data until it is recognized as an integer >0
Option Explicit
Dim fini, nombre
' loop until the data entered is correct
' the loop is controlled by a finite boolean, set to false at the start (= it's not finite)
fini=false
Do While Not fini
' we ask for the number
wscript.stdout.write "Tapez un nombre entier >0: "
' we read it
nombre=wscript.stdin.readLine
' test the actual type of data read
If isNumeric(nombre) Then
' is it a positive integer (number equal to its integer part)?
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' possible error msg
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmation
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' and end
wscript.quit 0
النتائج
تعليقات:
- تُرجع الدالة int(number) الجزء الصحيح من الرقم. والرقم الذي يساوي الجزء الصحيح منه هو عدد صحيح.
- من المثير للاهتمام ملاحظة أننا اضطررنا إلى استخدام الاختبار If (number - int(number)) = 0 And number > 0 لأن الاختبار If number = int(number) And number > 0 لم يسفر عن النتائج المتوقعة. لم يكتشف الأعداد الصحيحة الموجبة. نترك للقارئ اكتشاف السبب.
- اختبار If (number - int(number)) = 0 ليس موثوقًا تمامًا. لنلقِ نظرة على المثال التالي:
لا يتم تمثيل الأعداد الحقيقية بدقة بل تقريبياً. وهنا، أعادت العملية number-int(number) القيمة 0 بدقة الحاسوب.
4.2. التعبيرات العادية
تسمح لنا التعبيرات العادية باختبار تنسيق سلسلة. وبهذه الطريقة، يمكننا التحقق من أن السلسلة التي تمثل تاريخًا هي بتنسيق dd/mm/yy. للقيام بذلك، نستخدم نمطًا ونقارن السلسلة بهذا النمط. وبالتالي، في هذا المثال، يجب أن تكون d و m و y أرقامًا. يكون النمط لتنسيق تاريخ صالح هو "\d\d/\d\d/\d\d"، حيث يشير الرمز \d إلى رقم. الرموز التي يمكن استخدامها في النمط هي كما يلي (وثائق Microsoft):
الحرف | الوصف |
\ | يشير إلى الحرف التالي كحرف خاص أو حرفي. على سبيل المثال، "n" يقابل الحرف "n". "\n" يقابل حرف السطر الجديد. التسلسل "\\" يقابل "\"، بينما "\(" يقابل "(". |
^ | يطابق بداية الإدخال. |
$ | يتطابق مع نهاية الإدخال. |
* | يتطابق مع الحرف السابق صفر أو أكثر من مرة. وبالتالي، فإن "zo*" يتطابق مع "z" أو "zoo". |
+ | يتطابق مع الحرف السابق مرة واحدة أو أكثر. وبالتالي، فإن "zo+" يتطابق مع "zoo"، ولكنه لا يتطابق مع "z". |
? | يتطابق مع الحرف السابق صفر أو مرة واحدة. على سبيل المثال، "a?ve?" يتطابق مع "ve" في "lever". |
. | يتطابق مع أي حرف واحد، باستثناء حرف السطر الجديد. |
(النمط) | يبحث عن النمط ويخزن المطابقة. يمكن استرداد السلسلة الفرعية المطابقة من مجموعة Matches الناتجة باستخدام Item [0]...[n]. للعثور على المطابقات التي تحتوي على أحرف داخل أقواس ( )، استخدم "\(" أو "\)". |
x|y | يطابق إما x أو y. على سبيل المثال، "z|foot" يطابق "z" أو "foot". "(z|f)oo" يطابق "zoo" أو "foo". |
{n} | n هو عدد صحيح غير سالب. يطابق n مرة بالضبط من ظهور الحرف. على سبيل المثال، "o{2}" لا يطابق "o" في "Bob"، ولكنه يطابق أول حرفين "o" في "fooooot". |
{n,} | n هو عدد صحيح غير سالب. يطابق n مرة على الأقل من ظهور الحرف. على سبيل المثال، لا يطابق "o{2,}" حرف "o" في كلمة "Bob"، ولكنه يطابق جميع أحرف "o" في كلمة "fooooot". "o{1,}" يعادل "o+" و"o{0,}" يعادل "o*". |
{n,m} | m و n عددان صحيحان غير سالبين. يطابق ما لا يقل عن n وما لا يزيد عن m من تكرارات الحرف. على سبيل المثال، "o{1,3}" يطابق الأحرف "o" الثلاثة الأولى في "foooooot"، و "o{0,1}" يطابق "o?". |
[xyz] | مجموعة أحرف. يطابق أيًا من الأحرف المحددة. على سبيل المثال، يطابق "[abc]" الحرف "a" في "plat". |
[^xyz] | مجموعة أحرف سلبية. تتطابق مع أي حرف غير مدرج. على سبيل المثال، "[^abc]" تتطابق مع الحرف "p" في كلمة "plat". |
[a-z] | نطاق الأحرف. يطابق أي حرف في النطاق المحدد. على سبيل المثال، يطابق "[a-z]" أي حرف أبجدي صغير بين "a" و "z". |
[^m-z] | نطاق الأحرف السلبية. يطابق أي حرف غير موجود في النطاق المحدد. على سبيل المثال، يطابق "[^m-z]" أي حرف غير موجود بين "m" و "z". |
\b | يتطابق مع حدود الكلمة، أي الموضع بين الكلمة والمسافة. على سبيل المثال، يتطابق "er\b" مع "er" في "lever"، ولكنه لا يتطابق مع "er" في "verb". |
\B | يتطابق مع حد لا يمثل كلمة. يتطابق "en*t\B" مع "ent" في "bien entendu". |
\d | يتطابق مع حرف يمثل رقمًا. يعادل [0-9]. |
\D | يتطابق مع حرف ليس رقمًا. يعادل [^0-9]. |
\f | يتطابق مع حرف فاصل الأسطر. |
\n | يتطابق مع حرف السطر الجديد. |
\r | مكافئ لحرف إرجاع الحامل. |
\s | يتطابق مع أي مسافة بيضاء، بما في ذلك المسافة، وعلامة الجدولة، وفاصل الصفحة، وما إلى ذلك. يعادل "[ \f\n\r\t\v]". |
\S | يتطابق مع أي حرف غير مسافة بيضاء. يعادل "[^ \f\n\r\t\v]". |
\t | يتطابق مع حرف الجدولة. |
\v | يتطابق مع حرف الجدولة الرأسية. |
\w | يتطابق مع أي حرف يمثل كلمة ويشمل شرطة سفلية. يعادل "[A-Za-z0-9_]". |
\W | يتطابق مع أي حرف لا يمثل كلمة. يعادل "[^A-Za-z0-9_]". |
\num | يتطابق مع num، حيث num هو عدد صحيح موجب. يشير إلى التطابقات المخزنة. على سبيل المثال، يتطابق "(.)\1" مع حرفين متتاليين متطابقين. |
\n | يتطابق مع n، حيث n هو قيمة هروب ثمانية. يجب أن تتكون قيم الهروب الثمانية من 1 أو 2 أو 3 أرقام. على سبيل المثال، يتطابق كل من "\11" و "\011" مع حرف الجدولة. "\0011" يعادل "\001" و "1". يجب ألا تتجاوز قيم الهروب الثمانية 256. إذا تجاوزت ذلك، يتم أخذ أول رقمين فقط في الاعتبار في التعبير. يسمح باستخدام رموز ASCII في التعبيرات العادية. |
\xn | يتوافق مع n، حيث n هي قيمة هروب سداسية عشرية. يجب أن تتكون قيم الهروب السداسية العشرية من رقمين بالضبط. على سبيل المثال، "\x41" يتوافق مع "A". "\x041" يعادل "\x04" و "1". يسمح باستخدام رموز ASCII في التعبيرات العادية. |
قد يظهر عنصر في نمط مرة واحدة أو عدة مرات. دعونا نلقي نظرة على بعض الأمثلة التي تتضمن الرمز \d، الذي يمثل رقمًا واحدًا:
النمط | المعنى |
\d | رقم |
\d? | رقم واحد أو صفر |
\d* | رقم واحد أو أكثر |
\d+ | رقم واحد أو أكثر |
\d{2} | رقمان |
\d{3,} | 3 أرقام على الأقل |
\d{5,7} | ما بين 5 و 7 أرقام |
والآن، لنتخيل نموذجًا قادرًا على وصف التنسيق المتوقع لسلسلة نصية:
السلسلة المستهدفة | النمط |
تاريخ بتنسيق dd/mm/yy | \d{2}/\d{2}/\d{2} |
وقت بتنسيق hh:mm:ss | \d{2}:\d{2}:\d{2} |
عدد صحيح غير موقّع | \d+ |
سلسلة من المسافات، قد تكون فارغة | \s* |
عدد صحيح غير موقّع قد يسبقه أو يتبعه مسافات | \s*\d+\s* |
عدد صحيح قد يكون موقّعًا ويسبقه أو يتبعه مسافات | \s*[+|-]?\s*\d+\s* |
عدد حقيقي غير موقّع قد يسبقه أو يتبعه مسافات | \s*\d+(.\d*)?\s* |
عدد حقيقي قد يكون له إشارة ويسبقه أو يتبعه مسافات | \s*[+|]?\s*\d+(.\d*)?\s* |
سلسلة تحتوي على كلمة "just" | \bjuste\b |
يمكنك تحديد المكان الذي تريد البحث فيه عن النمط في السلسلة:
النمط | المعنى |
^النمط | يبدأ النمط السلسلة |
النمط$ | ينهي النمط السلسلة |
^النمط$ | يبدأ النمط السلسلة وينهيها |
النمط | يتم البحث عن النمط في أي مكان في السلسلة، بدءًا من البداية. |
سلسلة البحث | النمط |
سلسلة تنتهي بعلامة تعجب | !$ |
سلسلة تنتهي بنقطة | \.$ |
سلسلة تبدأ بالتسلسل // | ^// |
سلسلة تتكون من كلمة واحدة، قد تسبقها أو تتبعها مسافات | ^\s*\w+\s*$ |
سلسلة تتكون من كلمتين، يمكن أن تسبقها أو تليها مسافات | ^\s*\w+\s*\w+\s*$ |
سلسلة تحتوي على كلمة secret | \bsecret\b |
يمكن "استخراج" الأنماط الفرعية لنمط ما. وبالتالي، لا يمكننا فقط التحقق من أن سلسلة ما تتطابق مع نمط معين، بل يمكننا أيضًا استخراج العناصر المطابقة للأنماط الفرعية للنمط التي تم وضعها بين قوسين من تلك السلسلة. على سبيل المثال، إذا كنا نقوم بتحليل سلسلة تحتوي على تاريخ بتنسيق dd/mm/yy ونريد استخراج مكونات dd و mm و yy من ذلك التاريخ، فسنستخدم النمط (\d\d)/(\d\d)/(\d\d).
دعونا نلقي نظرة على هذا المثال لنرى كيفية القيام بذلك باستخدام VBScript.
- أولاً، نحتاج إلى إنشاء كائن RegExp (التعبير العادي)
- ثم نحدد النمط المراد اختباره
- قد ترغب في تجاهل حالة الأحرف (بشكل افتراضي، يتم التمييز بين الأحرف الكبيرة والصغيرة). هنا، لا يهم ذلك.
- قد ترغب في البحث عن النمط عدة مرات في السلسلة (بشكل افتراضي، لا يتم ذلك)
لا يكون البحث الشامل منطقيًا إلا إذا كان النمط المستخدم لا يشير إلى بداية السلسلة أو نهايتها.
- ثم نبحث عن جميع التطابقات للنمط في السلسلة:
تُرجع طريقة execute الخاصة بكائن RegExp مجموعة من كائنات match. يحتوي هذا الكائن على خاصية value تمثل السلسلة التي تتطابق مع النمط. إذا قمت بتعيين pattern.global=true، فقد تكون هناك عدة نتائج مطابقة. ولهذا السبب تكون نتيجة طريقة execute عبارة عن مجموعة من النتائج المطابقة.
- يتم تحديد عدد المطابقات بواسطة matches.count. إذا كان هذا الرقم 0، فهذا يعني أنه لم يتم العثور على النمط في أي مكان. يتم تحديد قيمة المطابقة #i بواسطة matches(i).value. إذا كان النمط يحتوي على أنماط فرعية بين قوسين، فإن عنصر matches(i) المطابق للقوس j في النمط هو matches(i).submatches(j).
يتم عرض كل هذا في المثال التالي:
البرنامج
' regular expression
' we want to check that a string contains a date in dd/mm/yy format
Option Explicit
Dim modele
' we define the
Set modele=new regexp
modele.pattern="\b(\d\d)/(\d\d)/(\d\d)\b" ' a date anywhere in the chain
modele.global=true ' we will search for the model several times in the chain
' the user specifies the string in which to search for the model
Dim chaine, correspondances, i
chaine=""
' loop as long as string<>"end"
Do While true
' the user is asked to type a text
wscript.stdout.writeLine "Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrêter : "
chaine=wscript.stdin.readLine
' fini si chaine=fin
If chaine="fin" Then Exit Do
' the string read is compared with the date template
Set correspondances=modele.execute(chaine)
' was a match found
If correspondances.count<>0 Then
' we have at least one match
For i=0 To correspondances.count-1
' the i correspondence is displayed
wscript.echo "J'ai trouvé la date " & correspondances(i).value
' we retrieve the sub-elements of correspondence 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
' no correspondence
wscript.echo "Je n'ai pas trouvé de date au format jj/mm/aa dans votre texte"
End If
Loop
' finish
wscript.quit 0
النتائج
باستخدام التعبيرات العادية، يمكن كتابة البرنامج الذي يتحقق مما إذا كانت المدخلات من لوحة المفاتيح هي بالفعل عدد صحيح موجب على النحو التالي:
البرنامج
' read data until it is recognized as a number
Option Explicit
Dim fini, nombre
' we define the model of a positive integer (which may be zero)
Dim modele
Set modele=new regexp
modele.pattern="^\s*\d+\s*$"
' loop until the data entered is correct
' the loop is controlled by a finite boolean, set to false at the start (= it's not finite)
fini=false
Do While Not fini
' we ask for the number
wscript.stdout.write "Tapez un nombre entier >0: "
' we read it
nombre=wscript.stdin.readLine
' test the format of the data read
Dim correspondances
Set correspondances=modele.execute(nombre)
' has the model been checked?
If correspondances.count<>0 Then
' it's an integer, but is it >0?
nombre=cint(nombre)
If nombre>0 Then
fini=true
End If
End If
' possible error msg
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmation
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' and end
wscript.quit 0
النتائج
قد يمثل العثور على التعبير النمطي الذي يسمح لنا بالتحقق مما إذا كانت سلسلة ما تتطابق مع نمط معين تحديًا حقيقيًا في بعض الأحيان. يتيح لك البرنامج التالي التدرب على ذلك. يطلب البرنامج نمطًا وسلسلة، ثم يشير إلى ما إذا كانت السلسلة تتطابق مع النمط أم لا.
البرنامج
' regular expression
' we want to check that a chain corresponds to a model
Option Explicit
' we define the
Dim modele
Set modele=new regexp
modele.global=true ' we will search for the model several times in the chain
' the user specifies the string in which to search for the model
Dim chaine, correspondances, i
Do While true
' the user is asked to type in a template
wscript.stdout.write "Tapez le modèle à tester et fin pour arrêter : "
modele.pattern=wscript.stdin.readLine
' finished?
If modele.pattern="fin" Then Exit Do
' the user is asked for the strings to be compared with the model
Do While true
' the user is asked to type in a template
wscript.stdout.writeLine "Tapez la chaîne à tester avec le modèle [" & modele.pattern & "] et fin pour arrêter : "
chaine=wscript.stdin.readLine
' finished?
If chaine="fin" Then Exit Do
' the string read is compared with the date template
Set correspondances=modele.execute(chaine)
' was a match found
If correspondances.count<>0 Then
' we have at least one match
For i=0 To correspondances.count-1
' the i correspondence is displayed
wscript.echo "J'ai trouvé la correspondance " & correspondances(i).value
Next
Else
' no correspondence
wscript.echo "Je n'ai pas trouvé de correspondance"
End If
Loop
Loop
' finish
wscript.quit 0
النتائج
4.3. معالجة أخطاء وقت التشغيل
هناك طريقة أخرى للتعامل مع أخطاء وقت التشغيل وهي السماح بحدوثها، وتلقي إشعار بها، ثم التعامل معها. عادةً، عند حدوث خطأ في وقت التشغيل، يعرض WSH رسالة خطأ ويتوقف البرنامج. هناك جملتان تسمحان لنا بتغيير هذا السلوك:
يخبر هذا البيان النظام (WSH) بأننا سنتعامل مع الأخطاء بأنفسنا. بعد هذا البيان، يتجاهل النظام أي أخطاء ببساطة.
يعيدنا هذا البيان إلى معالجة الأخطاء العادية.
عندما يكون البيان on error resume next نشطًا، يجب علينا معالجة أي أخطاء قد تحدث بأنفسنا. يساعدنا الكائن Err في القيام بذلك. يحتوي هذا الكائن على خصائص وأساليب متنوعة، وسنركز على الاثنين التاليين منها:
- number: عدد صحيح يمثل رقم آخر خطأ حدث. 0 تعني "لا يوجد خطأ"
- description: رسالة الخطأ التي كان النظام سيعرضها لو لم نصدر عبارة on error resume next
لنلقِ نظرة على المثال التالي:
البرنامج
' unhandled error
Option Explicit
Dim nombre
nombre=cdbl("abcd")
wscript.echo "nombre=" & nombre
النتائج
الآن دعونا نتعامل مع الخطأ:
البرنامج
' managed error
Option Explicit
Dim nombre
' we manage mistakes ourselves
On Error Resume Next
nombre=cdbl("abcd")
' was there a mistake?
If Err.number<>0 Then
wscript.echo "L'erreur [" & err.description & "] s'est produite"
On Error GoTo 0
wscript.quit 1
End If
' no error - returns to normal operation
On Error GoTo 0
wscript.echo "nombre=" & nombre
wscript.quit 0
النتائج
دعونا نعيد كتابة البرنامج لإدخال عدد صحيح >0 باستخدام هذه الطريقة الجديدة:
البرنامج
' read data until it is recognized as a number
Option Explicit
Dim fini, nombre
' loop until the data entered is correct
' the loop is controlled by a finite boolean, set to false at the start (= it's not finite)
fini=false
Do While Not fini
' we ask for the number
wscript.stdout.write "Tapez un nombre entier >0: "
' we read it
nombre=wscript.stdin.readLine
' test the format of the data read
On Error Resume Next
nombre=cdbl(nombre)
If err.number=0 Then
' no error it's a number
' returns to normal error handling mode
On Error GoTo 0
' is it an integer >0
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' returns to normal error handling mode
On Error GoTo 0
' possible error msg
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmation
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' and end
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. التطبيق على برنامج حساب الضرائب
سنعود إلى برنامج حساب الضرائب الذي كتبناه سابقًا، هذه المرة للتحقق من صحة الحجج التي تم تمريرها إلى البرنامج:
البرنامج
' calculating a taxpayer's tax liability
' the program must be called with three parameters: married children salary
' married: character Y if married, N if unmarried
' children: number of children
' salary: annual salary without cents
' no verification of data validity is performed, but we do
' check that there are three of them
' mandatory variable declaration
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)"
' we check that there are 3 arguments
Dim nbArguments
nbArguments=wscript.arguments.count
If nbArguments<>3 Then
' error msg
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect"
' stop with error code 1
wscript.quit 1
End If
' retrieve arguments and check their validity
' an argument is passed to the program without spaces in front and behind it
' use regular expressions to check data validity
Dim modele, correspondances
Set modele=new regexp
' marital status must be among the characters oOnN
modele.pattern="^[oOnN]$"
Set correspondances=modele.execute(wscript.arguments(0))
If correspondances.count=0 Then
' error
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect"
' we leave
wscript.quit 2
End If
' the value
Dim marie
If lcase(wscript.arguments(0)) = "o"Then
marie=true
Else
marie=false
End If
' children must be an integer >=0
modele.pattern="^\d{1,2}$"
Set correspondances=modele.execute(wscript.arguments(1))
If correspondances.count=0 Then
' error
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect"
' we leave
wscript.quit 3
End If
' the value
Dim enfants
enfants=cint(wscript.arguments(1))
' salary must be an integer >=0
modele.pattern="^\d{1,9}$"
Set correspondances=modele.execute(wscript.arguments(2))
If correspondances.count=0 Then
' error
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect"
' we leave
wscript.quit 4
End If
' the value
Dim salaire
salaire=clng(wscript.arguments(2))
' we define the data needed to calculate the tax in 3 tables
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)
' the number of shares is calculated
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
' calculate the family quota and taxable income
Dim revenu, qf
revenu=0.72*salaire
qf=revenu/nbParts
' tax calculation
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))
' the result is displayed
wscript.echo "impôt=" & impot
' leave without error
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