Skip to content

4. Обробка помилок

У програмуванні існує абсолютне правило: програма ніколи не повинна «вилітати» без попередження. Усі помилки, які можуть виникнути під час виконання програми, мають оброблятися, а також мають генеруватися відповідні повідомлення про помилки.

Якщо повернутися до прикладу з податками, який ми розглядали раніше, що станеться, якщо користувач введе будь-яке значення для кількості дітей? Розглянемо цей приклад:

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

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

Це і є так званий неконтрольований збій. Стався «збій» на операторі children=cint(wscript.arguments(1)), оскільки arguments(1) містив рядок «xyzt».

Перш ніж використовувати варіант, точний характер якого невідомий, слід перевірити його точний підтип. Це можна зробити різними способами:

  • перевірити фактичний тип даних, що містяться у варіанті, за допомогою функцій vartype або typename
  • використати регулярний вираз, щоб перевірити, чи вміст варіанта відповідає певному шаблону
  • дозволити виникненню помилки, а потім перехопити її та обробити

Розглянемо ці різні методи.

4.1. Визначення точного типу даних

Нагадаємо, що функції vartype або varname дозволяють визначити точний тип даних. Однак це не завжди є для нас великою допомогою. Наприклад, коли ми зчитуємо дані, введені з клавіатури, функції vartype та typename повідомлять нам, що це рядок символів, оскільки саме так розглядаються всі дані, введені з клавіатури. Це не дає нам інформації про те, чи можна, наприклад, вважати цей рядок дійсним числом. Тому для отримання доступу до такого роду інформації використовуються інші функції:

isNumeric(вираз)
повертає «true», якщо expression можна використовувати як число
isDate(вираз)
повертає «true», якщо вираз можна використовувати як дату
isEmpty(var)
повертає «true», якщо змінна var не була ініціалізована
isNull(var)
повертає «true», якщо змінна var містить недійсні дані
isArray(var)
повертає «true», якщо var є масивом
isObject(var)
повертає «true», якщо var є об’єктом

У наступному прикладі користувачеві пропонується вводити дані з клавіатури, доки вони не будуть розпізнані як число:

Програма
' читання даних, доки вони не будуть розпізнані як число

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 (число - int(число)) = 0 And число > 0, оскільки умова If число = int(число) And число > 0 не давала очікуваних результатів. Вона не виявляла додатних цілих чисел. Ми залишаємо читачеві можливість самостійно з’ясувати, чому.
  • Умова If (число - int(число)) = 0 не є цілком надійною. Розглянемо такий приклад виконання:
Tapez un nombre entier >0: 4,0000000000000000000000001

Merci pour le nombre entier >0 : 4,0000000000000000000000001

Дійсні числа не представлені точно, а наближено. І тут операція nombre-int(nombre) дала результат 0 з точністю, що відповідає можливостям комп’ютера.

4.2. Регулярні вирази

Регулярні вирази дають змогу перевіряти формат символьного рядка. Так, можна перевірити, чи рядок, що позначає дату, має формат дд/мм/рр. Для цього використовується шаблон, з яким порівнюється рядок. Отже, у цьому прикладі j, m та a мають бути цифрами. Шаблон дійсного формату дати — це «\d\d/\d\d/\d\d», де символ \d позначає цифру. У шаблоні можна використовувати такі символи (документація Microsoft):

Символ
Опис
\
Позначає наступний символ як спеціальний або літеральний. Наприклад, «n» відповідає символу «n». «\n» відповідає символу нового рядка. Послідовність «\\» відповідає «\», а «\(" відповідає «(».
^
Відповідає початку введення.
$
Відповідає кінцю введення.
*
Відповідає попередньому символу нуль або більше разів. Таким чином, «zo*» відповідає «z» або «zoo».
+
Відповідає попередньому символу один або кілька разів. Таким чином, «zo+» відповідає «zoo», але не «z».
?
Відповідає попередньому символу нуль або один раз. Наприклад, «a?ve?» відповідає «ve» у слові «lever».
.
Відповідає будь-якому окремому символу, крім символу нового рядка.
(шаблон)
Здійснює пошук modèle і запам’ятовує збіг. Відповідний підрядок можна витягти з отриманої колекції Matches за допомогою Item [0]...[n]. Щоб знайти збіги з символами в дужках ( ), використовуйте "\(" або "\)".
x|y
Відповідає або x, або y. Наприклад, «z|foot» відповідає «z» або «foot». «(z|f)oo» відповідає «zoo» або «foo».
{n}
n — це невід’ємне ціле число. Відповідає точно n, помноженому на символ. Наприклад, «o{2}» не відповідає «o» у слові «Bob», а відповідає двом першим «o» у слові «fooooot».
{n,}
n — це невід’ємне ціле число. Відповідає щонайменше n кратним цьому символу. Наприклад, «o{2,}» не відповідає «o» у слові «Bob», а відповідає всім «o» у слові «fooooot». «o{1,}» еквівалентно «o+», а «o{0,}» — «o*».
{n,m}
m та n — це невід’ємні цілі числа. Відповідає щонайменше n і щонайбільше m повторень символу. Наприклад, «o{1,3}» відповідає трьом першим «o» у слові «foooooot», а «o{0,1}» дорівнює «o?».
[xyz]
Набір символів. Відповідає одному з вказаних символів. Наприклад, «[abc]» відповідає «a» у слові «plat».
[^xyz]
Негативний набір символів. Відповідає будь-якому символу, що не вказано. Наприклад, «[^abc]» відповідає «p» у слові «plat».
[a-z]
Діапазон символів. Відповідає будь-якому символу у вказаному діапазоні. Наприклад, «[a-z]» відповідає будь-якій маленькій літері від «a» до «z».
[^m-z]
Негативний діапазон символів. Відповідає будь-якому символу, якого немає у вказаній послідовності. Наприклад, «[^m-z]» відповідає будь-якому символу, якого немає між «m» і «z».
\b
Відповідає межі, що позначає слово, іншими словами, позиції між словом і пробілом. Наприклад, «er\b» відповідає «er» у слові «lever», але не «er» у слові «verbe».
\B
Відповідає межі, що не позначає слово. «en*t\B» відповідає «ent» у слові «bien entendu».
\d
Відповідає символу, що позначає цифру. Еквівалентно [0-9].
\D
Відповідає символу, що не є цифрою. Еквівалентно [^0-9].
\f
Відповідає символу переходу на новий рядок.
\n
Відповідає символу нового рядка.
\r
Відповідає символу повернення каретки.
\s
Відповідає будь-якому пробілу, включаючи пробіл, табуляцію, перехід на нову сторінку тощо. Еквівалентно "[ \f\n\r\t\v]".
\S
Відповідає будь-якому символу, що не є пробілом. Еквівалентно «[^ \f\n\r\t\v]».
\t
Відповідає символу табуляції.
\v
Відповідає символу вертикального табуляції.
\w
Відповідає будь-якому символу, що позначає слово, включаючи підкреслення. Еквівалентно «[A-Za-z0-9_]».
\W
Відповідає будь-якому символу, що не позначає слово. Еквівалентно «[^A-Za-z0-9_]».
\num
Відповідає num, де num — це додатне ціле число. Посилається на збережені відповідності. Наприклад, «(.)\1» відповідає двом послідовним однаковим символам.
\n
Відповідає n, де n — це вісімкове значення екранування. Вісімкові значення екранування повинні складатися з 1, 2 або 3 цифр. Наприклад, «\11» і «\011» обидва відповідають символу табуляції. "\0011" еквівалентно "\001" & "1". Восьмиричні екрануючі значення не повинні перевищувати 256. Якщо це сталося, у виразі враховуватимуться лише перші дві цифри. Дозволяє використовувати коди ASCII у регулярних виразах.
\xn
Відповідає n, де n — це шістнадцяткове значення екранування. Шістнадцяткові екрануючі значення обов’язково мають складатися з двох цифр. Наприклад, «\x41» відповідає «A». «\x041» дорівнює «\x04» та «1». Дозволяє використовувати коди ASCII у регулярних виразах.

Елемент у шаблоні може зустрічатися один або кілька разів. Розглянемо кілька прикладів із символом \d, який позначає 1 цифру:

шаблон
значення
\d
одна цифра
\d?
0 або 1 цифра
\d*
0 або більше цифр
\d+
1 або більше цифр
\d{2}
2 цифри
\d{3,}
щонайменше 3 цифри
\d{5,7}
від 5 до 7 цифр

Тепер уявімо собі шаблон, здатний описати очікуваний формат рядка:

пошуковий рядок
модель
дата у форматі дд/мм/рр
\d{2}/\d{2}/\d{2}
час у форматі hh:mm:ss
\d{2}:\d{2}:\d{2}
ціле число без знака
\d+
послідовність пробілів, яка може бути порожньою
\s*
ціле число без знака, перед яким або після якого можуть бути пробіли
\s*\d+\s*
ціле число, яке може мати знак і перед яким або після якого можуть бути пробіли
\s*[+|-]?\s*\d+\s*
число з дійсної області без знака, перед яким або після якого можуть бути пробіли
\s*\d+(.\d*)?\s*
дійсне число, яке може мати знак і мати пробіли перед або після нього
\s*[+|]?\s*\d+(.\d*)?\s*
рядок, що містить слово «juste»
\bjuste\b
  

Можна вказати, де саме в рядку шукати шаблон:

шаблон
значення
^шаблон
модель починає рядок
шаблон$
шаблон завершує рядок
^шаблон$
шаблон починає і закінчує рядок
шаблон
шаблон шукається у всьому рядку, починаючи з його початку.
шуканий рядок
шаблон
рядок, що закінчується знаком оклику
!$
рядок, що закінчується крапкою
\.$
рядок, що починається з послідовності //
^//
рядок, що складається лише з одного слова, за яким можуть йти або перед яким можуть стояти пробіли
^\s*\w+\s*$
рядок, що містить два слова, за якими або перед якими можуть бути пробіли
^\s*\w+\s*\w+\s*$
рядок, що містить слово secret
\bsecret\b

Підмножини шаблону можна «витягувати». Таким чином, можна не тільки перевірити, чи рядок відповідає певному шаблону, але й витягнути з цього рядка елементи, що відповідають підмножинам шаблону, які були взяті в дужки. Отже, якщо ми аналізуємо рядок, що містить дату дд/мм/рр, і хочемо додатково виокремити елементи дд, мм, рр з цієї дати, ми використаємо шаблон (\d\d)/(\d\d)/(\d\d).

Давайте на цьому прикладі розглянемо, як це зробити за допомогою VBScript.

  • Спочатку нам потрібно створити об’єкт RegExp (Regular Expression)
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 у моделі, дорівнює 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=""
' виконується цикл, доки рядок <> "fin"
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
Результати
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

Знайти регулярний вираз, який дозволяє перевірити, чи відповідає рядок певному шаблону, іноді є справжнім викликом. Наступна програма дозволяє потренуватися. Вона запитує шаблон і рядок, а потім вказує, чи відповідає рядок шаблону.

Програма
' регулярний вираз

' потрібно перевірити, чи рядок відповідає шаблону

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

Перепишемо програму для введення цілого числа >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
  ' перевіряється формат прочитаних даних
  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