Skip to content

4. مدیریت خطا

در برنامه‌نویسی یک قانون مطلق وجود دارد: یک برنامه هرگز نباید به طور غیرمنتظره‌ای از کار بیفتد (crash). تمام خطاهایی که ممکن است در حین اجرای برنامه رخ دهند باید مدیریت شوند و پیام‌های خطای معناداری تولید شوند.

اگر به مثال مالیات مطرح‌شده در بالا بازگردیم، چه اتفاقی می‌افتد اگر کاربر برای تعداد فرزندان هر مقدار تصادفی را وارد کند؟ بیایید این مثال را بررسی کنیم:

1
2
3
C:\>cscript impots1.vbs o xyzt 200000

C:\impots1.vbs(33, 3) Erreur d'exécution Microsoft VBScript: Type incompatible: 'cint'

این چیزی است که به آن «کرش بدون رسیدگی» (unhandled crash) گفته می‌شود. یک کرش در عبارت children=cint(wscript.arguments(1)) رخ داد، زیرا arguments(1)</span> حاوی رشته «xyzt» بود.

قبل از استفاده از یک واریانت که ماهیت دقیق آن ناشناخته است، باید زیرنوع دقیق آن را بررسی کنید. راه‌های مختلفی برای انجام این کار وجود دارد:

  • نوع واقعی داده‌های موجود در یک واریانت را با استفاده از توابع vartype یا typename آزمایش کنید
  • از یک عبارت منظم (regular expression) برای بررسی اینکه محتوای واریانت با یک الگوی خاص مطابقت دارد، استفاده کنید
  • اجازه دهید خطا رخ دهد، سپس آن را رهگیری و مدیریت کنید

ما این روش‌های مختلف را بررسی خواهیم کرد.

4.1. تعیین نوع داده دقیق

به یاد داشته باشید که توابع vartype یا varname به شما امکان تعیین نوع دقیق داده را می‌دهند. این همیشه چندان مفید نیست. برای مثال، هنگامی که داده‌های وارد شده از طریق صفحه‌کلید را می‌خوانیم، توابع vartype و typename به ما خواهند گفت که این یک رشته کاراکتری است، زیرا تمام داده‌های وارد شده از طریق صفحه‌کلید به این صورت پردازش می‌شوند. این به ما نمی‌گوید که آیا این رشته، برای مثال، می‌تواند یک عدد معتبر در نظر گرفته شود یا خیر. بنابراین برای دسترسی به این نوع اطلاعات از توابع دیگری استفاده می‌کنیم:

isNumeric(expression)
اگر عبارت را بتوان به عنوان یک عدد استفاده کرد، مقدار true را برمی‌گرداند
isDate(expression)
در صورتی که عبارت را بتوان به عنوان یک تاریخ استفاده کرد، مقدار true را برمی‌گرداند
isEmpty(var)
در صورتی که متغیر var مقداردهی اولیه نشده باشد، مقدار true را برمی‌گرداند
isNull(var)
در صورتی که متغیر var حاوی داده‌های نامعتبر باشد، مقدار true را برمی‌گرداند
isArray(var)
در صورتی که var یک آرایه باشد، مقدار true را برمی‌گرداند
isObject(var)
اگر var یک شیء باشد، مقدار true را برمی‌گرداند

مثال زیر از کاربر می‌خواهد تا زمانی که داده‌ای به عنوان عدد شناسایی نشود، آن را از طریق صفحه‌کلید وارد کند:

برنامه
' داده‌ها را می‌خواند تا زمانی که به عنوان یک عدد شناسایی شوند

Option Explicit

Dim fini, nombre

' حلقه تا زمانی که داده‌های وارد شده صحیح باشند ادامه می‌یابد
'حلقه توسط یک متغیر بولی محدود کنترل می‌شود که در ابتدا روی false تنظیم شده است (= پایان‌یافته نیست)

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
نتایج
1
2
3
4
5
6
Tapez un nombre : a
Type de la donnée lue : String,8
Erreur, vous n'avez pas tapé un nombre. Recommencez svp...
Tapez un nombre : -12
Type de la donnée lue : String,8
Merci pour le nombre -12

تابع isNumeric به ما نمی‌گوید که یک عبارت عدد صحیح است یا خیر. برای به‌دست آوردن این اطلاعات، آزمون‌های اضافی لازم است. مثال زیر یک عدد صحیح بزرگ‌تر از 0 را درخواست می‌کند:

برنامه
' داده‌ها را تا زمانی که به‌عنوان یک عدد صحیح بزرگ‌تر از 0 شناخته شوند، می‌خوانیم

Option Explicit

Dim fini, nombre

'حلقه تا زمانی که داده‌ی واردشده صحیح باشد ادامه می‌یابد
'حلقه توسط یک متغیر بولی محدود کنترل می‌شود که در ابتدا روی false (= تمام نشده) تنظیم شده است

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
نتایج
1
2
3
4
5
6
7
8
Tapez un nombre entier >0: a
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: -1
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: 10.6
Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp...
Tapez un nombre entier >0: 12
Merci pour le nombre entier >0 : 12

توضیحات:

  • int(nombre) بخش صحیح یک عدد را برمی‌گرداند. عددی که برابر بخش صحیح خود باشد، یک عدد صحیح است.
  • جالب است بدانید که ما مجبور شدیم از شرط `If (number - int(number)) = 0 And number > 0` استفاده کنیم، زیرا شرط `If number = int(number) And number > 0` نتایج مورد انتظار را به دست نمی‌داد. این شرط نتوانست اعداد صحیح مثبت را تشخیص دهد. به خواننده واگذار می‌کنیم تا دلیل آن را کشف کند.
  • آزمون `If (number - int(number)) = 0` کاملاً قابل اعتماد نیست. بیایید به مثال اجرای زیر نگاهی بیندازیم:
Tapez un nombre entier >0: 4,0000000000000000000000001

Merci pour le nombre entier >0 : 4,0000000000000000000000001

اعداد حقیقی به طور دقیق نمایش داده نمی‌شوند، بلکه به صورت تقریبی نمایش داده می‌شوند. و در اینجا، عملیات nombre-int(nombre) با توجه به سطح دقت کامپیوتر، 0 را بازگردانده است.

4.2. بیان‌های منظم

بیان‌های منظم به ما امکان می‌دهند قالب یک رشته را بررسی کنیم. برای مثال، می‌توانیم تأیید کنیم که یک رشته نمایانگر یک تاریخ، در قالب dd/mm/yy است. برای این کار، از یک الگو استفاده کرده و رشته را با آن الگو مقایسه می‌کنیم. در این مثال، d، m و y باید اعداد باشند. الگو برای یک فرمت تاریخ معتبر بنابراین «\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 یک مقدار فرار اکتال است. مقادیر فرار اکتال باید شامل ۱، ۲ یا ۳ رقم باشند. به عنوان مثال، "\11" و "\011" هر دو به یک کاراکتر تب (tab) مطابقت دارند. "\0011" معادل "\001" و "1" است. مقادیر فرار اکتال نباید از ۲۵۶ تجاوز کنند. اگر این اتفاق بیفتد، تنها دو رقم اول در عبارت در نظر گرفته می‌شوند. امکان استفاده از کدهای ASCII در عبارات باقاعده را فراهم می‌کند.
\xn
مطابق با n است، که در آن n یک مقدار فرار هگزادسیمال است. مقادیر فرار هگزادسیمال باید از دو رقم تشکیل شوند. برای مثال، «\x41» معادل «A» است. «\x041» معادل «\x04» و «1» است. امکان استفاده از کدهای ASCII در عبارت‌های منظم فراهم است.

یک عنصر در یک الگو ممکن است یک یا چند بار ظاهر شود. بیایید به چند مثال مربوط به نماد \d که نماینده یک رقم است، نگاهی بیندازیم:

الگو
به معنای
\d
یک رقم
\d?
۰ یا ۱ رقم
اعداد دلخواه
۰ یا بیشتر رقم
یک یا چند رقم
۱ یا چند رقم
\d{2}
۲ رقم
\d{3,}
حداقل ۳ رقم
\d{5,7}
بین ۵ تا ۷ رقم

اکنون بیایید الگویی را در نظر بگیریم که قادر به توصیف قالب مورد انتظار برای یک رشته باشد:

رشته مقصد
الگو
یک تاریخ به فرمت dd/mm/yy
\d{2}/\d{2}/\d{2}
یک زمان در قالب ساعت:دقیقه:ثانیه
\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'
\bجوست\b
  

می‌توانید مشخص کنید که الگو را در کجای رشته جستجو کنید:

الگو
به معنی
^pattern
الگو در ابتدای رشته آغاز می‌شود
pattern$
الگو رشته را پایان می‌دهد
^الگو$
الگو رشته را شروع و پایان می‌دهد
الگو
الگو در هر جای رشته، از ابتدا جستجو می‌شود.
رشته جستجو
الگو
یک رشته که با علامت تعجب به پایان می‌رسد
!$
یک رشته که با نقطه پایان می‌یابد
\.$
یک رشته که با توالی // آغاز می‌شود
^//
یک رشته متشکل از یک کلمه واحد، که اختیاریاً قبل یا بعد از آن فاصله‌ها قرار می‌گیرند
^[ \t*]+[ \t*]$
یک رشته متشکل از دو کلمه، که اختیاریاً می‌تواند قبل یا بعد از آن فضا باشد
^\s*\w+\s*\w+\s*$
یک رشته حاوی کلمه 'secret'
\bsecret\b

زیرالگوها در یک الگو را می‌توان «استخراج» کرد. بنابراین، نه تنها می‌توانیم بررسی کنیم که آیا یک رشته با الگوی خاصی مطابقت دارد، بلکه می‌توانیم عناصر مربوط به زیرالگوهای الگو که در کروشه‌ها قرار گرفته‌اند را از آن رشته استخراج کنیم. بنابراین، اگر در حال تحلیل یک رشته حاوی تاریخ به فرمت dd/mm/yy باشیم و همچنین بخواهیم عناصر dd، mm و yy را از آن تاریخ استخراج کنیم، از الگوی (\d\d)/(\d\d)/(\d\d) استفاده خواهیم کرد.

بیایید این مثال را ببینیم تا ببینیم چگونه می‌توان این کار را با استفاده از VBScript انجام داد.

  • ابتدا باید یک شی RegExp (بیان منظم) ایجاد کنیم
set modele=new regexp
  • سپس، الگوی مورد آزمایش را تنظیم می‌کنیم
modele.pattern="(\d\d)/(\d\d)/(\d\d)"
  • ممکن است بخواهید به بزرگی و کوچکی حروف توجه نکنید (به طور پیش‌فرض، بین حروف بزرگ و کوچک تمایز قائل می‌شود). در این مورد، تفاوتی ندارد.
modele.IgnoreCase=true
  • ممکن است بخواهید الگو را چندین بار در رشته جستجو کنید (به طور پیش‌فرض، این کار انجام نمی‌شود)
modele.Global=true

جستجوی سراسری تنها زمانی منطقی است که الگوی مورد استفاده به شروع یا پایان رشته اشاره نکند.

  • سپس به دنبال تمام رخدادهای الگو در رشته می‌گردیم:
set correspondances=modele.execute(chaine)

متد execute یک شیء RegExp یک مجموعه از اشیاء از نوع match را برمی‌گرداند. این شیء دارای یک خاصیت value است که عنصر chaine متناظر با الگو است. اگر modele.global=true تنظیم شده باشد، ممکن است چندین تطابق وجود داشته باشد. به همین دلیل نتیجه متد execute یک مجموعه از تطابق‌ها است.

  • تعداد تطابق‌ها توسط correspondances.count مشخص می‌شود. اگر این مقدار 0 باشد، یعنی قالب در هیچ‌جا یافت نشده است. مقدار تطابق شماره i توسط correspondances(i).value مشخص می‌شود. اگر الگو شامل زیرالگوهایی در داخل پرانتز باشد، آنگاه عنصر correspondances(i) که به پرانتز j در الگو مربوط می‌شود، برابر است با matches(i).submatches(j).

تمام این موارد در مثال زیر نشان داده شده است:

برنامه
' بیان منظم

' ما می‌خواهیم بررسی کنیم که یک رشته حاوی تاریخ به فرمت dd/mm/yy باشد

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=""
' ما تا زمانی که رشته با "end" برابر نباشد، حلقه می‌زنیم
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
    ' در صورتی که رشته برابر "end" باشد، پایان می‌یابد
    If chaine="fin" Then Exit Do
    ' رشتهٔ خوانده‌شده را با الگوی تاریخ مقایسه می‌کند
    Set correspondances=modele.execute(chaine)
    'آیا تطابق یافت شده است؟
    If correspondances.count<>0 Then
        'حداقل یک تطابق وجود دارد
        For i=0 To correspondances.count-1
            'تطبیق نمایش داده می‌شود
            wscript.echo "J'ai trouvé la date " & correspondances(i).value
            ' زیرعنصرهای تطابق i را بازیابی می‌کند 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
نتایج
Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrÛter :
aujourd'hui on est le 01/01/01 et demain sera le 02/01/02
J'ai trouvé la date 01/01/01
Les éléments de la date 0 sont (01,01,01)
J'ai trouvé la date 02/01/02
Les éléments de la date 1 sont (02,01,02)

Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrÛter :
une date au format incorrect : 01/01/2002
Je n'ai pas trouvé de date au format jj/mm/aa dans votre texte

Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrÛter :
une suite de dates : 10/10/10, 11/11/11, 12/12/12
J'ai trouvé la date 10/10/10
Les éléments de la date 0 sont (10,10,10)
J'ai trouvé la date 11/11/11
Les éléments de la date 1 sont (11,11,11)
J'ai trouvé la date 12/12/12
Les éléments de la date 2 sont (12,12,12)

Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrÛter :
fin

با استفاده از عبارت‌های منظم، برنامه‌ای که بررسی می‌کند آیا ورودی صفحه‌کلید واقعاً یک عدد صحیح مثبت است، می‌تواند به صورت زیر نوشته شود:

برنامه
'داده‌ها را می‌خواند تا زمانی که به‌عنوان یک عدد شناسایی شود

Option Explicit

Dim fini, nombre

' فرمت یک عدد صحیح مثبت (که ممکن است صفر باشد) را تعریف می‌کند
Dim modele
Set modele=new regexp
modele.pattern="^\s*\d+\s*$"

'حلقه تا زمانی که داده‌ی واردشده صحیح باشد ادامه می‌یابد
'حلقه توسط یک متغیر بولی محدود کنترل می‌شود که در ابتدا روی false تنظیم شده است (= هنوز پایان نیافته)

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
نتایج
Tapez un nombre entier >0: 10.3
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: 0
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

یافتن عبارت منظم (regular expression) که به ما امکان می‌دهد بررسی کنیم آیا یک رشته با الگوی خاصی مطابقت دارد یا خیر، گاهی اوقات می‌تواند یک چالش واقعی باشد. برنامه زیر به شما امکان می‌دهد تمرین کنید. این برنامه از شما یک الگو و یک رشته می‌خواهد و سپس نشان می‌دهد که آیا آن رشته با الگو مطابقت دارد یا خیر.

برنامه
' بیان منظم

' ما می‌خواهیم بررسی کنیم که یک رشته با یک الگو مطابقت دارد

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
نتایج
Tapez le modèle à tester et fin pour arrêter : ^\s*\d+(\,\d+)*\s*$

Tapez la chaîne à tester avec le modèle [^\s*\d+(\,\d+)*\s*$] et fin pour arrêter :
18
J'ai trouvé la correspondance [18]

Tapez la chaîne à tester avec le modèle [^\s*\d+(\,\d+)*\s*$] et fin pour arrêter :
145.678
Je n'ai pas trouvé de correspondance

Tapez la chaîne à tester avec le modèle [^\s*\d+(\,\d+)*\s*$] et fin pour arrêter :
145,678
J'ai trouvé la correspondance [  145,678   ]

4.3. مدیریت خطاهای زمان اجرا

یک روش دیگر برای رسیدگی به خطاهای زمان اجرا این است که اجازه دهیم رخ دهند، از آن‌ها مطلع شویم و سپس به آن‌ها رسیدگی کنیم. معمولاً وقتی یک خطای زمان اجرا رخ می‌دهد، WSH یک پیام خطا نمایش می‌دهد و برنامه خاتمه می‌یابد. دو دستور به ما امکان می‌دهند این رفتار را تغییر دهیم:

on error resume next

این دستور به سیستم (WSH) می‌گوید که ما خودمان خطاها را مدیریت خواهیم کرد. پس از این دستور، هرگونه خطا به سادگی توسط سیستم نادیده گرفته می‌شود.

on error goto 0

این دستور رفتار عادی رسیدگی به خطا را بازیابی می‌کند.

وقتی عبارت «on error resume next» فعال باشد، ما باید هر خطایی را که ممکن است رخ دهد، خودمان مدیریت کنیم. شیء Err در این زمینه به ما کمک می‌کند. این شیء دارای خواص و متدهای مختلفی است که ما بر روی دو مورد زیر تمرکز خواهیم کرد:

  • number: یک عدد صحیح که نمایانگر شماره آخرین خطای رخ‌داده است. 0 به معنای «بدون خطا» است.
  • description: پیغام خطایی که سیستم در صورت صادر نکردن دستور `on error resume next` نمایش می‌داد

بیایید به مثال زیر نگاه کنیم:

برنامه
نتایج

'خطای رسیدگی‌نشده

Option Explicit
Dim nombre

nombre=cdbl("abcd")
wscript.echo "nombre=" & nombre
C:\ err5.vbs(6, 1) Erreur d'exécution Microsoft VBScript: Type incompatible: 'cdbl'

اکنون خطا را مدیریت کنیم:

برنامه
نتایج
'خطا رسیدگی شد

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
L'erreur [Type incompatible] s'est produite

بیایید برنامهٔ وارد کردن یک عدد صحیح بزرگ‌تر از ۰ را با استفاده از این روش جدید بازنویسی کنیم:

برنامه

' خواندن داده تا زمانی که به عنوان عدد شناسایی شود

Option Explicit

Dim fini, nombre

'حلقه تا زمانی که داده‌ی واردشده صحیح باشد ادامه می‌یابد
'حلقه توسط یک متغیر بولی محدود کنترل می‌شود که در ابتدا روی false تنظیم شده است (= پایان‌یافته نیست)

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. کاربرد در برنامه محاسبه مالیات

ما بار دیگر به برنامه محاسبه مالیات که قبلاً نوشته‌ایم بازمی‌گردیم، این بار برای بررسی اعتبار آرگومان‌های ارسال‌شده به برنامه:

برنامه

' محاسبه مالیات یک مؤدی
' برنامه باید با سه پارامتر فراخوانی شود: متأهل، تعداد فرزندان، حقوق
' married: کاراکتر '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)"

' ما بررسی می‌کنیم که ۳ آرگومان وجود دارد
  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
  
  ' فرزندان باید یک عدد صحیح ≥ ۰ باشند
  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))
  
  'داده‌های مورد نیاز برای محاسبه مالیات در ۳ جدول تعریف شده‌اند
  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