Skip to content

4. Hata Yönetimi

Programlamada mutlak bir kural vardır: bir program asla aniden "çökmemelidir". Programın çalışması sırasında ortaya çıkabilecek tüm hatalar yönetilmeli ve anlamlı hata mesajları üretilmelidir.

Daha önce ele aldığımız vergi örneğine geri dönersek, kullanıcı çocuk sayısı için rastgele bir değer girerse ne olur? Şu örneğe bakalım:

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

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

Buna "kontrolsüz çökme" denir. arguments(1), "xyzt" dizesini içerdiği için çocuklar=cint(wscript.arguments(1)) komutunda bir "çökme" meydana gelmiştir.

Tam olarak ne olduğunu bilmediğimiz bir varyantı kullanmadan önce, onun tam alt türünü kontrol etmeliyiz. Bunu çeşitli şekillerde yapabiliriz:

  • vartype veya typename işlevlerini kullanarak bir varyantta bulunan verinin gerçek türünü test etmek
  • bir düzenli ifade kullanarak varyantın içeriğinin belirli bir şablona uyup uymadığını kontrol etmek
  • hatanın oluşmasına izin verip, ardından hatayı yakalayarak yönetmek

Bu farklı yöntemleri inceleyeceğiz.

4.1. Bir verinin tam türünü belirleme

vartype veya varname işlevlerinin bir verinin tam türünü belirlemeye olanak sağladığını hatırlayalım. Ancak bu her zaman bize çok yardımcı olmaz. Örneğin, klavyeden girilen bir veriyi okuduğumuzda, vartype ve typename fonksiyonları bize bunun bir karakter dizisi olduğunu söyleyecektir; çünkü klavyeden girilen tüm veriler bu şekilde değerlendirilir. Bu, söz konusu dizinin örneğin geçerli bir sayı olarak kabul edilip edilemeyeceğini bize söylemez. Bu tür bilgilere erişmek için başka işlevler kullanırız:

isNumeric(ifade)
ifade bir sayı olarak kullanılabiliyorsa true değerini döndürür
isDate(ifade)
ifade bir tarih olarak kullanılabiliyorsa true değerini döndürür
isEmpty(var)
var değişkeni başlatılmamışsa true değerini döndürür
isNull(var)
var değişkeni geçersiz veriler içeriyorsa true değerini döndürür
isArray(var)
var bir dizi ise true değerini döndürür
isObject(var)
var bir nesne ise true değerini döndürür

Aşağıdaki örnek, girilen verinin sayı olarak tanınana kadar klavyeden veri girilmesini ister:

Program
' bir veri, sayı olarak tanınana kadar okunur

Option Explicit

Dim fini, nombre

' girdilen veri doğru olana kadar döngü devam eder
' döngü, başlangıçta "yanlış" olarak ayarlanan sonlu bir boole değeri ile kontrol edilir (= henüz bitmedi)

fini=false
Do While Not fini
    ' sayı sorulur
    wscript.stdout.write "Tapez un nombre : "
    ' sayı okunur
    nombre=wscript.stdin.readLine
    ' okuma sırasında veri türü mutlaka string olur
    wscript.echo "Type de la donnée lue : " & typename(nombre) & "," & vartype(nombre)
    ' Okunan verinin gerçek türü test edilir
    If isNumeric(nombre) Then 
        fini=true
    Else
        wscript.echo "Erreur, vous n'avez pas tapé un nombre. Recommencez svp..."
    End If
Loop

' onay
wscript.echo "Merci pour le nombre " & nombre

' ve son
wscript.quit 0
Sonuçlar
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 işlevi, bir ifadenin tamsayı olup olmadığını bize söylemez. Bu bilgiyi elde etmek için ek testler yapmak gerekir. Aşağıdaki örnek, >0 olan bir tamsayı ister:

Program
' veri, >0 bir tamsayı olarak tanınana kadar okunur

Option Explicit

Dim fini, nombre

' girdilen veri doğru olana kadar döngü devam eder
' döngü, başlangıçta "yanlış" olarak ayarlanan sonlu bir boole değeri ile kontrol edilir (= henüz bitmedi)

fini=false
Do While Not fini
    ' sayı sorulur
    wscript.stdout.write "Tapez un nombre entier >0: "
    ' sayı okunur
    nombre=wscript.stdin.readLine
    ' okunan verinin gerçek türü kontrol edilir
    If isNumeric(nombre) Then
        ' Bu, pozitif bir tamsayı mı (tamsayı kısmı ile eşit bir sayı)?
        If (nombre-int(nombre))=0 And nombre>0 Then
            fini=true
        End If
    End If
    ' olası hata mesajı
    If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop

' onay
wscript.echo "Merci pour le nombre entier >0 : " & nombre

' ve son
wscript.quit 0
Sonuçlar
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

Açıklamalar:

  • int(nombre), bir sayının tam sayısını verir. Tam sayısına eşit olan bir sayı, bir tam sayıdır.
  • İlginç bir şekilde, If (sayı - int(sayı)) = 0 And sayı > 0 testinin kullanılması gerektiği belirtilmelidir; çünkü If sayı = int(sayı) And sayı > 0 testi beklenen sonuçları vermiyordu. Bu test, pozitif tamsayıları algılamıyordu. Nedenini keşfetmeyi okuyucuya bırakıyoruz.
  • If (sayı - int(sayı)) = 0 testi tamamen güvenilir değildir. Aşağıdaki çalışma örneğine bakalım:
Tapez un nombre entier >0: 4,0000000000000000000000001

Merci pour le nombre entier >0 : 4,0000000000000000000000001

Reel sayılar tam olarak değil, yaklaşık olarak temsil edilir. Ve burada, nombre-int(nombre) işlemi, bilgisayarın hassasiyeti ölçüsünde 0 sonucunu vermiştir.

4.2. Düzenli ifadeler

Düzenli ifadeler, bir karakter dizisinin biçimini test etmemizi sağlar. Böylece, bir tarihi temsil eden dizinin gg/aa/yy biçiminde olup olmadığını kontrol edebiliriz. Bunun için bir şablon kullanılır ve dizi bu şablonla karşılaştırılır. Dolayısıyla bu örnekte, j, m ve a rakamlar olmalıdır. Geçerli bir tarih biçiminin şablonu "\d\d/\d\d/\d\d" şeklindedir; burada \d sembolü bir rakamı ifade eder. Şablonda kullanılabilecek semboller şunlardır (Microsoft belgeleri):

Karakter
Açıklama
\
Bir sonraki karakteri özel karakter veya literal olarak işaretler. Örneğin, "n" "n" karakterine karşılık gelir. "\n" bir satır sonu karakterine karşılık gelir. "\\" dizisi "\" karakterine karşılık gelirken, "\(" karakteri "(" karakterine karşılık gelir.
^
Girişin başlangıcına karşılık gelir.
$
Girişin sonuna karşılık gelir.
*
Önceki karakteri sıfır kez veya birden fazla kez ifade eder. Dolayısıyla, "zo*" hem "z" hem de "zoo" anlamına gelir.
+
Önceki karakteri bir veya daha fazla kez eşleştirir. Dolayısıyla, "zo+" "zoo" ile eşleşir, ancak "z" ile eşleşmez.
?
Önceki karakterle sıfır veya bir kez eşleşir. Örneğin, "a?ve?" "lever" kelimesindeki "ve" ile eşleşir.
.
Satır başı karakteri hariç, herhangi bir tek karakterle eşleşir.
(örnek)
modèle'i arar ve eşleşmeyi kaydeder. Eşleşen alt dize, elde edilen Matches koleksiyonundan Item [0]...[n] kullanılarak çıkarılabilir. Parantez ( ) içindeki karakterlerle eşleşmeleri bulmak için "\(" veya "\)" kullanın.
x|y
Ya x'e ya da y'e karşılık gelir. Örneğin, "z|foot" correspond à "z" ou à "foot". "(z|f)oo" ifadesi "zoo" ya da "foo" ifadesine karşılık gelir.
{n}
n, negatif olmayan bir tam sayıdır. Tam olarak n çarpı karakter değerine karşılık gelir. Örneğin, "o{2}", "Bob," içindeki "o" harfine değil, "fooooot" içindeki ilk iki "o" harfine karşılık gelir.
{n,}
n, negatif olmayan bir tamsayıdır. Karakterin en az n katına karşılık gelir. Örneğin, "o{2,}" "Bob" kelimesindeki "o" harfine değil, "fooooot" kelimesindeki tüm "o" harflerine karşılık gelir. "o{1,}" "o+" ile eşdeğerdir ve "o{0,}" "o*" ile eşdeğerdir.
{n,m}
m ve n, negatif olmayan tamsayılardır. Karakterin en az n ve en fazla m kez tekrarlandığı durumlara karşılık gelir. Örneğin, "o{1,3}", "foooooot" kelimesindeki ilk üç "o" karakterine karşılık gelir ve "o{0,1}", "o?" karakterine eşittir.
[xyz]
Karakter kümesi. Belirtilen karakterlerden birine karşılık gelir. Örneğin, "[abc]", "plat" kelimesindeki "a" harfine karşılık gelir.
[^xyz]
Negatif karakter kümesi. Belirtilmeyen tüm karakterlere karşılık gelir. Örneğin, "[^abc]", "plat" kelimesindeki "p" harfine karşılık gelir.
[a-z]
Karakter aralığı. Belirtilen dizideki tüm karakterlere karşılık gelir. Örneğin, "[a-z]", "a" ile "z" arasındaki tüm küçük harf karakterlerine karşılık gelir.
[^m-z]
Negatif karakter aralığı. Belirtilen dizide bulunmayan tüm karakterlere karşılık gelir. Örneğin, "[^m-z]", "m" ile "z" arasında bulunmayan tüm karakterlere karşılık gelir.
\b
Bir kelimeyi temsil eden sınırla, başka bir deyişle bir kelime ile boşluk arasındaki konuma karşılık gelir. Örneğin, "er\b", "lever" kelimesindeki "er"e karşılık gelir, ancak "verbe" kelimesindeki "er"e karşılık gelmez.
\B
Bir kelimeyi temsil etmeyen bir sınırla eşleşir. "en*t\B", "bien entendu" kelimesindeki "ent" ile eşleşir.
\d
Bir rakamı temsil eden bir karaktere karşılık gelir. [0-9] ile eşdeğerdir.
\D
Rakam olmayan bir karaktere karşılık gelir. [^0-9] ile eşdeğerdir.
\f
Sayfa sonu karakterine karşılık gelir.
\n
Satır sonu karakterine karşılık gelir.
\r
Satır başı karakterine karşılık gelir.
\s
Boşluk, sekme, sayfa sonu vb. dahil olmak üzere tüm boşluk karakterlerine karşılık gelir. "[ \f\n\r\t\v]" ile eşdeğerdir.
\S
Beyaz olmayan tüm boşluk karakterlerine karşılık gelir. "[^ \f\n\r\t\v]" ile eşdeğerdir.
\t
Bir sekme karakterine karşılık gelir.
\v
Dikey sekme karakterine karşılık gelir.
\w
Bir kelimeyi temsil eden ve alt çizgi içeren herhangi bir karaktere karşılık gelir. "[A-Za-z0-9_]" ile eşdeğerdir.
\W
Bir kelimeyi temsil etmeyen herhangi bir karaktere karşılık gelir. "[^A-Za-z0-9_]" ile eşdeğerdir.
\num
num'e karşılık gelir; burada num pozitif bir tamsayıdır. Kaydedilmiş eşleşmelere atıfta bulunur. Örneğin, "(.)\1" ardışık iki aynı karaktere karşılık gelir.
\n
n'e karşılık gelir; burada n sekizlik bir kaçış değeridir. Sekizlik kaçış değerleri 1, 2 veya 3 basamaklı olmalıdır. Örneğin, "\11" ve "\011" her ikisi de bir sekme karakterine karşılık gelir. "\0011", "\001" ve "1"e eşittir. Sekizlik kaçış değerleri 256'yı aşmamalıdır. Aşılması durumunda, ifadede yalnızca ilk iki rakam dikkate alınır. ASCII kodlarının düzenli ifadelerde kullanılmasına olanak tanır.
\xn
n'e karşılık gelir; burada n onaltılık bir kaçış değeridir. Onaltılık kaçış değerleri mutlaka iki basamaklı olmalıdır. Örneğin, "\x41" "A" harfine karşılık gelir. "\x041" ise "\x04" ve "1" değerlerinin birleşimine eşittir. ASCII kodlarının düzenli ifadelerde kullanılmasına izin verir.

Bir şablondaki öğe, 1 veya daha fazla kopya halinde bulunabilir. 1 rakamı temsil eden \d sembolüyle ilgili birkaç örneği ele alalım:

şablon
anlam
\d
bir rakam
\d?
0 veya 1 rakam
\d*
0 veya daha fazla rakam
\d+
1 veya daha fazla rakam
\d{2}
2 rakam
\d{3,}
en az 3 rakam
\d{5,7}
5 ile 7 arasında rakam

Şimdi, bir karakter dizisi için beklenen biçimi tanımlayabilen bir model düşünelim:

aranan dize
model
gg/mm/yy formatında bir tarih
\d{2}/\d{2}/\d{2}
hh:mm:ss biçiminde bir saat
\d{2}:\d{2}:\d{2}
işaretsiz bir tamsayı
\d+
boş olabilir bir boşluk dizisi
\s*
önünde veya arkasında boşluk bulunabilen işaretsiz bir tamsayı
\s*\d+\s*
işareti olan bir tamsayı; başında veya sonunda boşluk olabilir
\s*[+|-]?\s*\d+\s*
önünde veya arkasında boşluk bulunabilen işaretsiz bir gerçek sayı
\s*\d+(.\d*)?\s*
işareti olan veya olmayan bir gerçek sayı; başında veya sonunda boşluk olabilir
\s*[+|]?\s*\d+(.\d*)?\s*
"juste" kelimesini içeren bir dize
\bjuste\b
  

Dizgide kalıbın nerede aranacağını belirtebiliriz:

desen
anlam
^örnek
model, dizginin başında yer alır
model$
şablon dizgiyi sonlandırır
^desen$
şablon dizgiyi başlatır ve bitirir
desen
desen, dizgenin başından başlayarak her yerinde aranır.
aranan dize
desen
ünlem işaretiyle biten bir dize
!$
nokta ile biten bir dize
\.$
// dizisiyle başlayan bir dize
^//
yalnızca bir kelimeden oluşan ve isteğe bağlı olarak öncesinde veya sonrasında boşluklar bulunan bir dize
^\s*\w+\s*$
önünde veya arkasında boşluk olabilecek iki kelimeden oluşan bir dize
^\s*\w+\s*\w+\s*$
"secret" kelimesini içeren bir dize
\bsecret\b

Bir şablonun alt kümeleri "çıkarılabilir". Böylece, bir dizgenin belirli bir şablona uyup uymadığını kontrol etmekle kalmaz, aynı zamanda bu dizgede parantezlerle çevrelenmiş şablonun alt kümelerine karşılık gelen öğeleri de çıkarabiliriz. Örneğin, gg/aa/yyyy tarihini içeren bir dizgiyi analiz ediyorsak ve bu tarihin gg, aa, yyyy öğelerini de ayıklamak istiyorsak, (\d\d)/(\d\d)/(\d\d) kalıbını kullanırız.

Bu örnek üzerinden VBScript ile nasıl çalışılacağını inceleyelim.

  • Öncelikle bir RegExp (Düzenli İfade) nesnesi oluşturmamız gerekiyor
set modele=new regexp
  • ardından test edilecek şablonu belirleriz
modele.pattern="(\d\d)/(\d\d)/(\d\d)"
  • Büyük ve küçük harfleri ayırt etmemeyi tercih edebiliriz (varsayılan olarak ayırt edilir). Burada bunun bir önemi yoktur.
modele.IgnoreCase=true
  • Dizgide şablonu birden fazla kez aramak isteyebilirsiniz (varsayılan olarak bu yapılmaz)
modele.Global=true

Kapsamlı arama, yalnızca kullanılan desen dizgenin başına veya sonuna atıfta bulunmuyorsa anlamlıdır.

  • Bu durumda, dizideki tüm desen eşleşmeleri aranır:
set correspondances=modele.execute(chaine)

execute nesnesinin RegExp yöntemi, match türünde bir nesne koleksiyonu döndürür. Bu nesnenin value özelliği, modele karşılık gelen chaine öğesidir. modele.global=true yazılmışsa, birden fazla eşleşme olabilir. Bu nedenle, execute yönteminin sonucu bir eşleşme koleksiyonudur.

  • Eşleşme sayısı correspondances.count olarak verilir. Bu sayı 0 ise, şablon hiçbir yerde bulunamamıştır. i numaralı eşleşmenin değeri correspondances(i).value ile verilir. Şablonda parantez içinde alt şablonlar varsa, şablondaki j numaralı paranteze karşılık gelen correspondances(i) öğesi, correspondances(i).submatches(j) olur.

Tüm bunlar aşağıdaki örnekte gösterilmiştir:

Program
' düzenli ifade

' bir dizgenin gg/aa/yy biçiminde bir tarih içerdiğini doğrulamak istiyoruz

Option Explicit
Dim modele

' şablonu tanımlıyoruz
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

' Şablonu arayacağımız dizgiyi kullanıcı girer
Dim chaine, correspondances, i

chaine=""
' dize <> "son" olduğu sürece döngü devam eder
Do While true
    ' kullanıcıdan bir metin girmesini istiyoruz
    wscript.stdout.writeLine "Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrêter : "
    chaine=wscript.stdin.readLine
    ' dize = "son" ise işlem sona erer
    If chaine="fin" Then Exit Do
    ' okunan dize, tarih şablonuyla karşılaştırılır
    Set correspondances=modele.execute(chaine)
    ' bir eşleşme bulundu mu
    If correspondances.count<>0 Then
        ' en az bir eşleşme var
        For i=0 To correspondances.count-1
            ' i eşleşmesini görüntülüyor
            wscript.echo "J'ai trouvé la date " & correspondances(i).value
            ' i eşleşmesinin alt öğelerini alıyoruz
            wscript.echo "Les éléments de la date " & i & " sont (" & correspondances(i).submatches(0) & "," _
            & correspondances(i).submatches(1) & "," & correspondances(i).submatches(2) & ")"
        Next
    Else
        ' eşleşme yok
        wscript.echo "Je n'ai pas trouvé de date au format jj/mm/aa dans votre texte"
    End If
Loop

' işlem tamamlandı
wscript.quit 0
Sonuçlar
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

Düzenli ifadeler kullanılarak, klavyeden girilen bir değerin pozitif bir tamsayı olup olmadığını kontrol eden program şu şekilde yazılabilir:

Program
' bir veri, sayı olarak tanınana kadar okunur

Option Explicit

Dim fini, nombre

' pozitif bir tamsayı modeli tanımlanır (ancak sıfır da olabilir)
Dim modele
Set modele=new regexp
modele.pattern="^\s*\d+\s*$"

' girdilen veri doğru olana kadar döngü devam eder
' döngü, başlangıçta "yanlış" olarak ayarlanan sonlu bir boole değeri ile kontrol edilir (= henüz bitmedi)

fini=false
Do While Not fini
    ' sayı sorulur
    wscript.stdout.write "Tapez un nombre entier >0: "
    ' sayı okunur
    nombre=wscript.stdin.readLine
    ' okunan verinin biçimi kontrol edilir
    Dim correspondances
    Set correspondances=modele.execute(nombre)
    ' Şablon doğrulandı mı?
    If correspondances.count<>0 Then
        ' bu bir tamsayı, peki >0 mı?
        nombre=cint(nombre)
        If nombre>0 Then
            fini=true
        End If
    End If
    ' olası hata mesajı
    If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop

' onay
wscript.echo "Merci pour le nombre entier >0 : " & nombre

' ve son
wscript.quit 0
Sonuçlar
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

Bir dizgenin belirli bir kalıba uyup uymadığını kontrol etmemizi sağlayan düzenli ifadeyi bulmak bazen gerçek bir zorluktur. Aşağıdaki program bu konuda alıştırma yapmanıza olanak tanır. Program, bir kalıp ve bir dizge girilmesini ister ve ardından dizgenin kalıba uyup uymadığını belirtir.

Program
' düzenli ifade

' bir dizgenin bir şablona uyup uymadığını kontrol etmek istiyoruz

Option Explicit

' deseni tanımlıyoruz
Dim modele
Set modele=new regexp
modele.global=true                      ' on recherchera le modèle plusieurs fois dans la chaîne

' deseni arayacağımız dizgiyi kullanıcı girer
Dim chaine, correspondances, i

Do While true
    ' kullanıcıdan bir şablon girmesi istenir
    wscript.stdout.write "Tapez le modèle à tester et fin pour arrêter : "
    modele.pattern=wscript.stdin.readLine
    ' Bitti mi?
    If modele.pattern="fin" Then Exit Do
        ' kullanıcıdan şablonla karşılaştırılacak dizeleri girmesi istenir
        Do While true
            ' kullanıcıdan bir şablon girmesi istenir
            wscript.stdout.writeLine "Tapez la chaîne à tester avec le modèle [" & modele.pattern & "] et fin pour arrêter : "
            chaine=wscript.stdin.readLine
            ' bitti mi?
            If chaine="fin" Then Exit Do
            ' okunan dize, tarih şablonuyla karşılaştırılıyor
            Set correspondances=modele.execute(chaine)
            ' Bir eşleşme bulundu mu?
            If correspondances.count<>0 Then
                ' en az bir eşleşme var
                For i=0 To correspondances.count-1
                    ' i eşleşmesi görüntüleniyor
                    wscript.echo "J'ai trouvé la correspondance " & correspondances(i).value
                Next
            Else
                ' eşleşme yok
                wscript.echo "Je n'ai pas trouvé de correspondance"
            End If
    Loop
Loop

' işlem tamamlandı
wscript.quit 0
Sonuçlar
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. Çalıştırma hatalarını yakalama

Çalışma zamanı hatalarını yönetmenin bir başka yöntemi de, hataların gerçekleşmesine izin vermek, hatalar hakkında uyarı almak ve ardından bunları yönetmektir. Normalde, çalışma zamanında bir hata oluştuğunda, WSH bir hata mesajı görüntüler ve program durdurulur. Bu davranışı değiştirmemizi sağlayan iki komut vardır:

on error resume next

Bu komut, sisteme (WSH) hataları kendimiz yöneteceğimizi bildirir. Bu komuttan sonra, sistem tarafından tüm hatalar basitçe göz ardı edilir.

on error goto 0

Bu komut, bizi normal hata yönetimi işleyişine geri döndürür.

"on error resume next" komutu etkin olduğunda, ortaya çıkabilecek hataları kendimiz yönetmemiz gerekir. Err nesnesi bu konuda bize yardımcı olur. Bu nesnenin çeşitli özellikleri ve yöntemleri vardır; bunlardan şu ikisini ele alacağız:

  • number: meydana gelen son hatanın numarasını gösteren bir tamsayı. 0, "hata yok" anlamına gelir
  • description: on error resume next komutu verilmemiş olsaydı sistemin görüntüleyeceği hata mesajı

Aşağıdaki örneğe bakalım:

Program
Sonuçlar

' yönetilemeyen hata

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'

Şimdi hatayı ele alalım:

Program
Sonuçlar
' hatayı işledik

Option Explicit
Dim nombre

' hataları kendimiz yönetiyoruz
On Error Resume Next
nombre=cdbl("abcd")
' Hata mı oluştu?
If Err.number<>0 Then
    wscript.echo "L'erreur [" & err.description & "] s'est produite"
    On Error GoTo 0
    wscript.quit 1
End If
' hata yok - normal çalışmaya dönülüyor
On Error GoTo 0
wscript.echo "nombre=" & nombre
wscript.quit 0
L'erreur [Type incompatible] s'est produite

>0 olan bir tamsayı girişi yapan programı bu yeni yöntemle yeniden yazalım:

Program

' bir veri, sayı olarak tanınana kadar okunur

Option Explicit

Dim fini, nombre

' girdilen veri doğru olana kadar döngü devam eder
' döngü, başlangıçta "yanlış" olarak ayarlanan sonlu bir boole değeri ile kontrol edilir (= henüz bitmedi)

fini=false
Do While Not fini
  ' sayı sorulur
  wscript.stdout.write "Tapez un nombre entier >0: "
  ' sayı okunur
  nombre=wscript.stdin.readLine
  ' okunan verinin biçimi kontrol edilir
  On Error Resume Next
  nombre=cdbl(nombre)
  If err.number=0 Then
    ' hata yok, bu bir sayı
    ' normal hata işleme moduna geri dönülür
    On Error GoTo 0
    ' bu >0 bir tamsayı mı
    If (nombre-int(nombre))=0 And nombre>0 Then
      fini=true
    End If
  End If
  ' normal hata işleme moduna geri dönülüyor
  On Error GoTo 0
  ' olası hata mesajı
  If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop

' onay
wscript.echo "Merci pour le nombre entier >0 : " & nombre

' ve son
wscript.quit 0
Sonuçlar
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

Açıklamalar:

  • Bu yöntem bazen kullanılabilecek tek yöntemdir. Bu durumda, hataya neden olabilecek komut dizisi tamamlandığında normal hata yönetimi moduna geri dönmeyi unutmamak gerekir.

4.4. Vergi hesaplama programına uygulama

Daha önce yazdığımız vergi hesaplama programını, bu sefer programa aktarılan argümanların geçerliliğini kontrol etmek amacıyla yeniden ele alıyoruz:

Program

' bir vergi mükellefinin vergisinin hesaplanması
' program üç parametre ile çağrılmalıdır: evli, çocuk sayısı, maaş
' evli: evliyse O, evli değilse N karakteri
' çocuklar: çocuk sayısı
' maaş: sentler hariç yıllık maaş

' verilerin geçerliliği kontrol edilmez, ancak
' çocuk sayısının tam olarak üç olup olmadığı kontrol edilir

' değişkenlerin bildirilmesi zorunludur
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 argüman olup olmadığı kontrol edilir
  Dim nbArguments
  nbArguments=wscript.arguments.count
  If nbArguments<>3 Then
    ' hata mesajı
    wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect"
    ' hata kodu 1 ile sonlandırma
    wscript.quit 1
  End If
  
' argümanların geçerliliğini kontrol ederek alınır
' bir argüman, önüne ve arkasına boşluk eklenmeden programa aktarılır
' verilerin geçerliliğini kontrol etmek için düzenli ifadeler kullanılacak
  Dim modele, correspondances
  Set modele=new regexp

  ' medeni durum, oOnN karakterlerinden oluşmalıdır
  modele.pattern="^[oOnN]$"
  Set correspondances=modele.execute(wscript.arguments(0))
  If correspondances.count=0 Then
    ' hata
    wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect"
    ' çıkış
    wscript.quit 2
  End If
  ' değer alınır
  Dim marie
  If lcase(wscript.arguments(0)) = "o"Then
    marie=true
  Else
    marie=false
  End If
  
  ' çocuk sayısı 0'dan büyük bir tamsayı olmalıdır
  modele.pattern="^\d{1,2}$"
  Set correspondances=modele.execute(wscript.arguments(1))
  If correspondances.count=0 Then
    ' hata
    wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect"
    ' çıkılıyor
    wscript.quit 3
  End If
  ' değeri alınıyor
  Dim enfants
  enfants=cint(wscript.arguments(1))

  ' maaş, 0'dan büyük veya 0'a eşit bir tamsayı olmalıdır
  modele.pattern="^\d{1,9}$"
  Set correspondances=modele.execute(wscript.arguments(2))
  If correspondances.count=0 Then
    ' hata
    wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect"
    ' çıkılıyor
    wscript.quit 4
  End If
  ' değeri alıyoruz
  Dim salaire
  salaire=clng(wscript.arguments(2))
  
  ' vergi hesaplaması için gerekli veriler 3 tabloya tanımlanıyor
  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)

  ' pay sayısını hesaplıyoruz
  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
  
  ' aile katsayısı ve vergilendirilebilir gelir hesaplanıyor
  Dim revenu, qf
  revenu=0.72*salaire
  qf=revenu/nbParts
  
  ' vergi hesaplanır
  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))
  
  ' sonuç görüntülenir
  wscript.echo "impôt=" & impot
  
  ' hata olmadan çıkılıyor
  wscript.quit 0
Sonuçlar
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