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:
| 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 |
| 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 |
| 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
- 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.
- Dizgide şablonu birden fazla kez aramak isteyebilirsiniz (varsayılan olarak bu yapılmaz)
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:
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.
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
|