4. Gestão de erros
Na programação, existe uma regra absoluta: um programa nunca deve «travar» de forma inesperada. Todos os erros que possam ocorrer durante a execução do programa devem ser geridos e devem ser geradas mensagens de erro significativas.
Se retomarmos o exemplo dos impostos abordado anteriormente, o que acontece se o utilizador introduzir qualquer valor para o número de filhos? Vejamos este exemplo:
| C:\>cscript impots1.vbs o xyzt 200000
C:\impots1.vbs(33, 3) Erreur d'exécution Microsoft VBScript: Type incompatible: 'cint'
|
É a isto que se chama uma falha súbita. Ocorreu uma «falha» na instrução children=cint(wscript.arguments(1)) porque arguments(1) continha a cadeia «xyzt».
Antes de utilizar um variante cuja natureza exata desconhecemos, é necessário verificar o seu subtipo exato. Isto pode ser feito de várias formas:
- testar o tipo real dos dados contidos numa variante com as funções vartype ou typename
- utilizar uma expressão regular para verificar se o conteúdo da variante corresponde a um determinado padrão
- deixar que o erro ocorra, interceptá-lo e, em seguida, tratá-lo
Analisamos estes diferentes métodos.
4.1. Conhecer o tipo exato de um dado
Recorde-se que as funções vartype ou varname permitem determinar o tipo exato de um dado. No entanto, isso nem sempre nos é de grande utilidade. Por exemplo, quando lemos um dado introduzido pelo teclado, as funções vartype e typename indicam-nos que se trata de uma cadeia de caracteres, pois é assim que qualquer dado introduzido pelo teclado é considerado. Isso não nos diz se essa cadeia pode, por exemplo, ser considerada um número válido. Utilizamos, então, outras funções para aceder a este tipo de informação:
isNumeric(expressão) | retorna «verdadeiro» se a expressão puder ser utilizada como um número |
isDate(expressão) | retorna verdadeiro se a expressão puder ser utilizada como uma data |
isEmpty(var) | retorna verdadeiro se a variável var não tiver sido inicializada |
isNull(var) | retorna verdadeiro se a variável var contiver dados inválidos |
isArray(var) | retorna verdadeiro se var for um array |
isObject(var) | retorna verdadeiro se var for um objeto |
O exemplo seguinte solicita que se introduza um valor através do teclado até que este seja reconhecido como um número:
Programa |
' leitura de um dado até que este seja reconhecido como um número
Option Explicit
Dim fini, nombre
' repete-se o ciclo enquanto os dados introduzidos não estiverem corretos
' o ciclo é controlado por uma variável booleana, inicialmente definida como falso (= ainda não terminou)
fini=false
Do While Not fini
' solicita-se o número
wscript.stdout.write "Tapez un nombre : "
' lê-se o número
nombre=wscript.stdin.readLine
' o tipo é necessariamente string durante a leitura
wscript.echo "Type de la donnée lue : " & typename(nombre) & "," & vartype(nombre)
' verifica-se o tipo real dos dados lidos
If isNumeric(nombre) Then
fini=true
Else
wscript.echo "Erreur, vous n'avez pas tapé un nombre. Recommencez svp..."
End If
Loop
' confirmação
wscript.echo "Merci pour le nombre " & nombre
' e fim
wscript.quit 0
|
Resultados |
| 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
|
|
A função isNumeric não nos indica se uma expressão é um número inteiro ou não. Para obter essa informação, é necessário realizar testes adicionais. O exemplo seguinte solicita um número inteiro >0:
Programa |
' leitura de um dado até que este seja reconhecido como um número inteiro >0
Option Explicit
Dim fini, nombre
' repete-se o ciclo enquanto os dados introduzidos não estiverem corretos
' o ciclo é controlado por uma variável booleana definida como falso no início (= ainda não terminou)
fini=false
Do While Not fini
' solicita-se o número
wscript.stdout.write "Tapez un nombre entier >0: "
' lê-se o número
nombre=wscript.stdin.readLine
' verifica-se se o tipo de dados lidos é real
If isNumeric(nombre) Then
' será um inteiro (número igual à sua parte inteira) positivo?
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' eventual mensagem de erro
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmação
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' e fim
wscript.quit 0
|
Resultados |
| 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
|
|
Comentários:
- int(nombre) fornece a parte inteira de um número. Um número igual à sua parte inteira é um número inteiro.
- É interessante notar que foi necessário utilizar o teste If (número - int(número)) = 0 And número > 0, porque o teste If número = int(número) And número > 0 não produzia os resultados esperados. Não detetava os números inteiros positivos. Deixamos ao leitor a tarefa de descobrir porquê.
- O teste If (número - int(número)) = 0 não é totalmente fiável. Vejamos o seguinte exemplo de execução:
Tapez un nombre entier >0: 4,0000000000000000000000001
Merci pour le nombre entier >0 : 4,0000000000000000000000001
|
Os números reais não são representados de forma exata, mas sim de forma aproximada. E, neste caso, a operação nombre-int(nombre) resultou em 0, com a precisão do computador.
4.2. As expressões regulares
As expressões regulares permitem-nos verificar o formato de uma cadeia de caracteres. Assim, podemos verificar se uma cadeia que representa uma data está no formato dd/mm/aa. Para tal, utiliza-se um padrão e compara-se a cadeia com esse padrão. Assim, neste exemplo, j, m e a devem ser algarismos. O modelo de um formato de data válido é, então, «\d\d/\d\d/\d\d», em que o símbolo \d representa um algarismo. Os símbolos que podem ser utilizados num modelo são os seguintes (documentação da Microsoft):
Caractere | Descrição |
\ | Indica que o caractere seguinte é um caractere especial ou literal. Por exemplo, «n» corresponde ao caractere «n». «\n» corresponde a um caractere de nova linha. A sequência «\\» corresponde a «\», enquanto que «\»(» corresponde a «(». |
^ | Corresponde ao início da entrada. |
$ | Corresponde ao fim da entrada. |
* | Corresponde ao carácter anterior zero ou mais vezes. Assim, «zo*» corresponde a «z» ou a «zoo». |
+ | Corresponde ao carácter anterior uma ou mais vezes. Assim, «zo+» corresponde a «zoo», mas não a «z». |
? | Corresponde ao carácter anterior zero ou uma vez. Por exemplo, «a?ve?» corresponde a «ve» em «lever». |
. | Corresponde a qualquer carácter único, exceto ao carácter de nova linha. |
(padrão) | Procura o modèle e memoriza a correspondência. A subcadeia correspondente pode ser extraída da coleção Matches obtida, utilizando o Item [0]...[n]. Para encontrar correspondências com caracteres entre parênteses ( ), utilize "\(" ou "\)". |
x|y | Corresponde a x ou a y. Por exemplo, «z|foot» corresponde a «z» ou a «foot». «(z|f)oo» corresponde a «zoo» ou a «foo». |
{n} | n é um número inteiro não negativo. Corresponde exatamente a n vezes o carácter. Por exemplo, «o{2}» não corresponde a «o» em «Bob», mas aos dois primeiros «o» em «fooooot». |
{n,} | n é um número inteiro não negativo. Corresponde a, pelo menos, n vezes o carácter. Por exemplo, «o{2,}» não corresponde ao «o» em «Bob», mas a todos os «o» em «fooooot». «o{1,}» equivale a «o+» e «o{0,}» equivale a «o*». |
{n,m} | m e n são números inteiros não negativos. Corresponde a, no mínimo, n e, no máximo, m vezes o carácter. Por exemplo, «o{1,3}» corresponde aos três primeiros «o» em «foooooot» e «o{0,1}» equivale a «o?». |
[xyz] | Conjunto de caracteres. Corresponde a um dos caracteres indicados. Por exemplo, «[abc]» corresponde a «a» em «plat». |
[^xyz] | Conjunto de caracteres negativo. Corresponde a qualquer caractere não indicado. Por exemplo, «[^abc]» corresponde a «p» em «plat». |
[a-z] | Intervalo de caracteres. Corresponde a qualquer caractere da série especificada. Por exemplo, «[a-z]» corresponde a qualquer letra minúscula entre «a» e «z». |
[^m-z] | Intervalo de caracteres negativo. Corresponde a qualquer caractere que não se encontre na série especificada. Por exemplo, «[^m-z]» corresponde a qualquer caractere que não se encontre entre «m» e «z». |
\b | Corresponde a um delimitador que representa uma palavra, ou seja, à posição entre uma palavra e um espaço. Por exemplo, «er\b» corresponde a «er» em «lever», mas não a «er» em «verbe». |
\B | Corresponde a um limite que não representa uma palavra. «en*t\B» corresponde a «ent» em «bien entendu». |
\d | Corresponde a um carácter que representa um algarismo. É equivalente a [0-9]. |
\D | Corresponde a um carácter que não representa um algarismo. É equivalente a [^0-9]. |
\f | Corresponde a um carácter de salto de página. |
\n | Corresponde a um carácter de nova linha. |
\r | Corresponde a um carácter de retorno de carro. |
\s | Corresponde a qualquer espaço em branco, incluindo espaço, tabulação, salto de página, etc. É equivalente a «[ \f\n\r\t\v]». |
\S | Corresponde a qualquer caractere de espaço não em branco. Equivale a «[^ \f\n\r\t\v]». |
\t | Corresponde a um carácter de tabulação. |
\v | Corresponde a um carácter de tabulação vertical. |
\w | Corresponde a qualquer carácter que represente uma palavra e inclua um sublinhado. É equivalente a «[A-Za-z0-9_]». |
\W | Corresponde a qualquer carácter que não represente uma palavra. É equivalente a «[^A-Za-z0-9_]». |
\num | Corresponde a num, em que num é um número inteiro positivo. Refere-se às correspondências memorizadas. Por exemplo, «(.)\1» corresponde a dois caracteres idênticos consecutivos. |
\n | Corresponde a n, em que n é um valor de escape octal. Os valores de escape octais devem ter 1, 2 ou 3 dígitos. Por exemplo, "\11" e "\011" correspondem ambos a um carácter de tabulação. "\0011" equivale a "\001" e "1". Os valores de escape octais não devem exceder 256. Se tal acontecer, apenas os dois primeiros dígitos serão considerados na expressão. Permite utilizar os códigos ASCII em expressões regulares. |
\xn | Corresponde a n, em que n é um valor de escape hexadecimal. Os valores de escape hexadecimais têm de incluir obrigatoriamente dois dígitos. Por exemplo, «\x41» corresponde a «A». «\x041» equivale a «\x04» e «1». Permite utilizar os códigos ASCII em expressões regulares. |
Um elemento num modelo pode estar presente uma ou mais vezes. Vejamos alguns exemplos relacionados com o símbolo \d, que representa um algarismo:
modelo | significado |
\d | um algarismo |
\d? | 0 ou 1 dígito |
\d* | 0 ou mais dígitos |
\d+ | 1 ou mais dígitos |
\d{2} | 2 algarismos |
\d{3,} | pelo menos 3 algarismos |
\d{5,7} | entre 5 e 7 dígitos |
Imaginemos agora o modelo capaz de descrever o formato esperado para uma cadeia de caracteres:
cadeia procurada | modelo |
uma data no formato dd/mm/aa | \d{2}/\d{2}/\d{2} |
uma hora no formato hh:mm:ss | \d{2}:\d{2}:\d{2} |
um número inteiro sem sinal | \d+ |
uma sequência de espaços, que pode estar vazia | \s* |
um número inteiro sem sinal que pode ser precedido ou seguido de espaços | \s*\d+\s* |
um número inteiro que pode ser com sinal e precedido ou seguido de espaços | \s*[+|-]?\s*\d+\s* |
um número real sem sinal que pode ser precedido ou seguido de espaços | \s*\d+(.\d*)?\s* |
um número real que pode ser com sinal e precedido ou seguido de espaços | \s*[+|]?\s*\d+(.\d*)?\s* |
uma cadeia de caracteres que contenha a palavra «justo» | \bjusto\b |
| | |
É possível especificar onde se procura o padrão na cadeia:
padrão | significado |
^padrão | o padrão inicia a cadeia |
padrão$ | o modelo termina a cadeia |
^padrão$ | o modelo inicia e termina a cadeia |
padrão | o padrão é procurado em toda a cadeia, começando pelo início da mesma. |
cadeia procurada | padrão |
uma cadeia que termina com um ponto de exclamação | !$ |
uma cadeia que termina com um ponto | \.$ |
uma cadeia que começa com a sequência // | ^// |
uma cadeia que contém apenas uma palavra, eventualmente seguida ou precedida de espaços | ^\s*\w+\s*$ |
uma cadeia que contenha duas palavras, eventualmente seguidas ou precedidas de espaços | ^\s*\w+\s*\w+\s*$ |
uma cadeia que contenha a palavra «secret» | \bsecret\b |
Os subconjuntos de um padrão podem ser «recuperados». Assim, não só é possível verificar se uma cadeia corresponde a um padrão específico, como também é possível recuperar nessa cadeia os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Assim, se analisarmos uma cadeia que contenha uma data dd/mm/aa e, além disso, quisermos extrair os elementos dd, mm e aa dessa data, utilizaremos o padrão (\d\d)/(\d\d)/(\d\d).
Vejamos, com este exemplo, como se procede com o VBScript.
- Primeiro, temos de criar um objeto RegExp (Expressão Regular)
- depois, definimos o padrão a testar
modele.pattern="(\d\d)/(\d\d)/(\d\d)"
- Podemos optar por não distinguir entre maiúsculas e minúsculas (por predefinição, essa distinção é feita). Neste caso, isso não tem qualquer importância.
- pode-se querer procurar o padrão várias vezes na cadeia (por predefinição, isso não acontece)
Uma pesquisa global só faz sentido se o padrão utilizado não se referir ao início ou ao fim da cadeia de caracteres.
- Procura-se, então, todas as correspondências do padrão na cadeia:
set correspondances=modele.execute(chaine)
O método execute de um objeto RegExp devolve uma coleção de objetos do tipo «match». Este objeto possui uma propriedade «value» que corresponde ao elemento de chaine que corresponde ao padrão. Se tiver sido definido modele.global=true, podem existir várias correspondências. É por isso que o resultado do método execute é uma coleção de correspondências.
- O número de correspondências é dado por correspondances.count. Se esse número for 0, significa que o modelo não foi encontrado em lado nenhum. O valor da correspondência n.º i é dado por correspondances(i).value. Se o modelo contiver submodelos entre parênteses, então o elemento de correspondances(i) correspondente ao parêntese j do modelo é correspondências(i).submatches(j).
Tudo isto é ilustrado no exemplo seguinte:
Programa |
' expressão regular
' pretende-se verificar se uma cadeia de caracteres contém uma data no formato dd/mm/aa
Option Explicit
Dim modele
' definimos o modelo
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
' é o utilizador que fornece a cadeia de caracteres na qual se irá procurar o modelo
Dim chaine, correspondances, i
chaine=""
' executa-se um ciclo enquanto a cadeia de caracteres for diferente de "fim"
Do While true
' pede-se ao utilizador que introduza um texto
wscript.stdout.writeLine "Tapez un texte contenant des dates au format jj/mm/aa et fin pour arrêter : "
chaine=wscript.stdin.readLine
' termina se a cadeia for igual a «fin»
If chaine="fin" Then Exit Do
' compara-se a cadeia lida com o modelo da data
Set correspondances=modele.execute(chaine)
' encontrou-se uma correspondência?
If correspondances.count<>0 Then
' há pelo menos uma correspondência
For i=0 To correspondances.count-1
' é apresentada a correspondência i
wscript.echo "J'ai trouvé la date " & correspondances(i).value
' recuperam-se os subelementos da correspondência 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
' não há correspondência
wscript.echo "Je n'ai pas trouvé de date au format jj/mm/aa dans votre texte"
End If
Loop
' fim
wscript.quit 0
|
Resultados |
| 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
|
|
Com expressões regulares, o programa que verifica se uma entrada do teclado é efetivamente um número inteiro positivo poderia ser escrito da seguinte forma:
Programa |
' leitura de um dado até que este seja reconhecido como um número
Option Explicit
Dim fini, nombre
' define-se o modelo de um número inteiro positivo (que pode, no entanto, ser nulo)
Dim modele
Set modele=new regexp
modele.pattern="^\s*\d+\s*$"
' repete-se o ciclo enquanto os dados introduzidos não estiverem corretos
' o ciclo é controlado por uma variável booleana, inicialmente definida como falsa (= ainda não terminou)
fini=false
Do While Not fini
' solicita-se o número
wscript.stdout.write "Tapez un nombre entier >0: "
' lê-se o número
nombre=wscript.stdin.readLine
' verifica-se o formato dos dados lidos
Dim correspondances
Set correspondances=modele.execute(nombre)
' O modelo foi verificado?
If correspondances.count<>0 Then
' é um número inteiro, mas será que é >0?
nombre=cint(nombre)
If nombre>0 Then
fini=true
End If
End If
' eventual mensagem de erro
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmação
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' e fim
wscript.quit 0
|
Resultados |
| 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
|
|
Encontrar a expressão regular que nos permite verificar se uma cadeia corresponde efetivamente a um determinado padrão é, por vezes, um verdadeiro desafio. O programa seguinte permite praticar. Solicita um padrão e uma cadeia e indica, em seguida, se a cadeia corresponde ou não ao padrão.
Programa |
' expressão regular
' queremos verificar se uma cadeia de caracteres corresponde a um padrão
Option Explicit
' define-se o padrão
Dim modele
Set modele=new regexp
modele.global=true ' on recherchera le modèle plusieurs fois dans la chaîne
' é o utilizador que fornece a cadeia de caracteres na qual se irá procurar o padrão
Dim chaine, correspondances, i
Do While true
' pede-se ao utilizador que introduza um padrão
wscript.stdout.write "Tapez le modèle à tester et fin pour arrêter : "
modele.pattern=wscript.stdin.readLine
' Terminou?
If modele.pattern="fin" Then Exit Do
' pede-se ao utilizador as cadeias a comparar com o modelo
Do While true
' pede-se ao utilizador que introduza um padrão
wscript.stdout.writeLine "Tapez la chaîne à tester avec le modèle [" & modele.pattern & "] et fin pour arrêter : "
chaine=wscript.stdin.readLine
' Concluído?
If chaine="fin" Then Exit Do
' compara-se a cadeia lida com o modelo da data
Set correspondances=modele.execute(chaine)
' foi encontrada uma correspondência?
If correspondances.count<>0 Then
' há pelo menos uma correspondência
For i=0 To correspondances.count-1
' exibe-se a correspondência i
wscript.echo "J'ai trouvé la correspondance " & correspondances(i).value
Next
Else
' não há correspondência
wscript.echo "Je n'ai pas trouvé de correspondance"
End If
Loop
Loop
' concluído
wscript.quit 0
|
Resultados |
| 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. Interceptar erros de execução
Outro método de gestão de erros de execução consiste em deixar que estes ocorram, ser notificado da sua ocorrência e, só então, tratá-los. Normalmente, quando ocorre um erro durante a execução, o WSH apresenta uma mensagem de erro e o programa é interrompido. Duas instruções permitem-nos alterar este comportamento:
Esta instrução indica ao sistema (WSH) que iremos gerir os erros nós próprios. Após esta instrução, qualquer erro é simplesmente ignorado pelo sistema.
Esta instrução restabelece o funcionamento normal da gestão de erros.
Quando a instrução «on error resume next» está ativa, temos de gerir nós próprios os erros que possam ocorrer. O objeto Err ajuda-nos nessa tarefa. Este objeto possui várias propriedades e métodos, dos quais destacamos os dois seguintes:
- number: um número inteiro que corresponde ao número do último erro ocorrido. 0 significa «nenhum erro»
- description: a mensagem de erro que o sistema teria exibido se não tivéssemos emitido a instrução «on error resume next»
Vejamos o exemplo seguinte:
Programa | Resultados |
' erro não tratado
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'
|
|
Vamos agora tratar do erro:
Programa | Resultados |
' erro tratado
Option Explicit
Dim nombre
' nós próprios tratamos dos erros
On Error Resume Next
nombre=cdbl("abcd")
' houve algum erro?
If Err.number<>0 Then
wscript.echo "L'erreur [" & err.description & "] s'est produite"
On Error GoTo 0
wscript.quit 1
End If
' sem erro — regressamos ao funcionamento normal
On Error GoTo 0
wscript.echo "nombre=" & nombre
wscript.quit 0
|
| L'erreur [Type incompatible] s'est produite
|
|
Vamos reescrever o programa para introduzir um número inteiro >0 utilizando este novo método:
Programa |
' leitura de um dado até que este seja reconhecido como um número
Option Explicit
Dim fini, nombre
' o ciclo repete-se enquanto os dados introduzidos não estiverem corretos
' o ciclo é controlado por uma variável booleana finita, definida como falsa no início (= ainda não terminou)
fini=false
Do While Not fini
' solicita-se o número
wscript.stdout.write "Tapez un nombre entier >0: "
' lê-se o número
nombre=wscript.stdin.readLine
' verifica-se o formato dos dados lidos
On Error Resume Next
nombre=cdbl(nombre)
If err.number=0 Then
' sem erros, é um número
' regressa-se ao modo normal de gestão de erros
On Error GoTo 0
' será um número inteiro >0?
If (nombre-int(nombre))=0 And nombre>0 Then
fini=true
End If
End If
' regressa-se ao modo normal de gestão de erros
On Error GoTo 0
' eventual mensagem de erro
If Not fini Then wscript.echo "Erreur, vous n'avez pas tapé un nombre entier >0. Recommencez svp..."
Loop
' confirmação
wscript.echo "Merci pour le nombre entier >0 : " & nombre
' e fim
wscript.quit 0
|
Resultados |
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
|
Comentários:
- Este método é, por vezes, o único utilizável. Nesse caso, não se deve esquecer de regressar ao modo normal de gestão de erros assim que a sequência de instruções suscetível de gerar o erro estiver concluída.
4.4. Aplicação ao programa de cálculo de impostos
Retomamos o programa de cálculo de impostos já escrito para, desta vez, verificar a validade dos argumentos passados ao programa:
Programa |
' cálculo do imposto de um contribuinte
' o programa deve ser chamado com três parâmetros: casado, filhos, salário
' casado: caractere O se casado, N se solteiro
' filhos: número de filhos
' salário: salário anual sem os cêntimos
' não é efetuada qualquer verificação da validade dos dados, mas
' verifica-se se existem efetivamente três
' declaração obrigatória das variáveis
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)"
' verifica-se se existem 3 argumentos
Dim nbArguments
nbArguments=wscript.arguments.count
If nbArguments<>3 Then
' mensagem de erro
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect"
' interrupção com código de erro 1
wscript.quit 1
End If
' recuperam-se os argumentos, verificando a sua validade
' um argumento é transmitido ao programa sem espaços à frente nem atrás
' serão utilizadas expressões regulares para verificar a validade dos dados
Dim modele, correspondances
Set modele=new regexp
' o estado civil deve estar entre os caracteres oOnN
modele.pattern="^[oOnN]$"
Set correspondances=modele.execute(wscript.arguments(0))
If correspondances.count=0 Then
' erro
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect"
' sair
wscript.quit 2
End If
' recuperamos o valor
Dim marie
If lcase(wscript.arguments(0)) = "o"Then
marie=true
Else
marie=false
End If
' «filhos» deve ser um número inteiro >=0
modele.pattern="^\d{1,2}$"
Set correspondances=modele.execute(wscript.arguments(1))
If correspondances.count=0 Then
' erro
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect"
' sair
wscript.quit 3
End If
' recuperar o valor
Dim enfants
enfants=cint(wscript.arguments(1))
' o salário deve ser um número inteiro >=0
modele.pattern="^\d{1,9}$"
Set correspondances=modele.execute(wscript.arguments(2))
If correspondances.count=0 Then
' erro
wscript.echo syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect"
' sair
wscript.quit 4
End If
' recuperamos o valor
Dim salaire
salaire=clng(wscript.arguments(2))
' definem-se os dados necessários para o cálculo do imposto em 3 tabelas
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)
' calcula-se o número de quotas
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
' calcula-se o quociente familiar e o rendimento tributável
Dim revenu, qf
revenu=0.72*salaire
qf=revenu/nbParts
' calcula-se o imposto
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))
' exibe-se o resultado
wscript.echo "impôt=" & impot
' sai sem erros
wscript.quit 0
|
Resultados |
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
|