Skip to content

4. Classes .NET comumente utilizadas

Apresentamos aqui algumas classes da plataforma .NET que são de interesse, mesmo para um principiante. Primeiro, mostramos como obter informações sobre as centenas de classes disponíveis.

4.1. Procurar ajuda com o SDK.NET

4.1.1. wincv

Se tiver instalado apenas o SDK e não o Visual Studio.NET, pode utilizar o programa wincv.exe, que normalmente se encontra no diretório do SDK, por exemplo, C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1. Ao iniciar este utilitário, é apresentada a seguinte interface:

Digite o nome da classe desejada em (1). Isto apresenta várias opções possíveis em (2). Selecione a opção adequada e o resultado aparecerá em (3) — neste caso, a classe HashTable. Este método é adequado se souber o nome da classe que está a procurar. Se pretender explorar a lista de opções oferecidas pela plataforma .NET, pode utilizar o ficheiro HTML StartHere.htm, que também se encontra diretamente na pasta de instalação do SSK.Net, por exemplo, C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.

Image

O link «Documentação do .NET Framework SDK» é o que deve seguir para obter uma visão geral das classes .NET:

Image

A partir daí, clique no link [Biblioteca de Classes]. Este contém uma lista de todas as classes .NET:

Image

Por exemplo, vamos seguir o link System.Collections. Este namespace contém várias classes que implementam coleções, incluindo a classe HashTable:

Image

Vamos seguir o link HashTable abaixo:

Image

Chegamos à seguinte página:

Image

Repare na posição do cursor abaixo. Ele está a apontar para um link que permite especificar a linguagem desejada, neste caso o Visual Basic.

Aqui encontrará o protótipo da classe, bem como exemplos de utilização. Clique no link [Hashtable, Members] abaixo:

Image

Obtemos a descrição completa da classe:

Image

Este método é a melhor forma de explorar o SDK e as suas classes. A ferramenta WinCV é útil quando já conhece um pouco sobre a classe, mas se esqueceu de alguns dos seus membros. O WinCV permite-lhe então encontrar rapidamente a classe e os seus membros.

4.2. Pesquisar ajuda sobre classes com o VS.NET

Aqui estão algumas dicas para encontrar ajuda no Visual Studio.NET

4.2.1. Opção de Ajuda

Selecione a opção [?] no menu.

Image

Aparece a seguinte janela:

Image

Na lista suspensa, pode selecionar um filtro de ajuda. Aqui, vamos escolher o filtro [Visual Basic].

Image

Existem dois tipos de ajuda úteis:

  • ajuda sobre a própria linguagem VB.NET (sintaxe)
  • ajuda sobre as classes .NET que podem ser utilizadas pela linguagem VB.NET

A ajuda da linguagem VB.NET está acessível através de [Visual Studio.NET/Visual Basic e Visual C#/Referência/Visual Basic]:

Image

Isto abre a seguinte página de ajuda:

Image

A partir daí, os vários subtítulos fornecem ajuda sobre diferentes tópicos do VB.NET. Preste especial atenção aos tutoriais do VB.NET:

Image

Para aceder às várias classes da plataforma .NET, selecione a ajuda [Visual Studio.NET/.NET Framework].

Image

Vamos concentrar-nos, em particular, na secção [Referência/Biblioteca de Classes]:

Image

Suponhamos que estamos interessados na classe [ArrayList]. Esta encontra-se no namespace [System.Collections]. É importante saber isto; caso contrário, preferiríamos o método de pesquisa descrito abaixo. Obtemos a seguinte ajuda:

Image

A ligação [ArrayList, Class] apresenta uma visão geral da classe:

Image

Este tipo de página existe para todas as classes. Apresenta um resumo da classe com exemplos. Para obter uma descrição dos membros da classe, siga o link [ArrayList, membros]:

Image

4.2.2. Ajuda/Índice

Image

A opção [Ajuda/Índice] permite-lhe procurar ajuda mais específica do que o método anterior. Basta digitar a palavra-chave que procura:

Image

A vantagem deste método em relação ao anterior é que não precisa de saber onde encontrar o que procura no sistema de ajuda. Este é provavelmente o método preferido para pesquisas específicas, enquanto o outro método é mais adequado para explorar tudo o que o sistema de ajuda tem para oferecer.

4.3. A Classe String

A classe String possui muitas propriedades e métodos. Aqui estão alguns deles:

Propriedade pública ReadOnly Length como Integer
número de caracteres na string
Propriedade pública de leitura apenas
Chars(ByVal index As Integer) As Char
propriedade indexada por padrão. [String].Chars(i) é o i-ésimo caractere da cadeia
Função pública EndsWith(ByVal value As String)
As Boolean
Retorna true se a cadeia terminar com o valor
Função Pública StartsWith(ByVal valor As String)
Como Booleano
Retorna true se a cadeia de caracteres começar com o valor
Sobrecarga Função Pública Equals(ByVal valor
As String) As Boolean
retorna true se a string for igual a value
Sobrecarga a função pública IndexOf(ByVal valor
As String) As Integer
retorna a primeira posição na string onde o valor da string é encontrado — a pesquisa começa a partir do caractere 0
Sobrecarga da função pública IndexOf(ByVal valor
As String, ByVal startIndex As Integer) As Integer
Retorna a posição da primeira ocorrência do valor da string na string — a pesquisa começa no índice de caractere startIndex
Sobrecarga Função Pública Partilhada
Join(ByVal separator As String, ByVal value()
As String) As String
método de classe — retorna uma string resultante da concatenação dos valores na matriz value com o separador separator
Sobrecarga Função Pública Replace(ByVal oldChar
As Char, ByVal newChar As Char) As String
retorna uma cópia da string atual onde o caractere oldChar foi substituído pelo caractere newChar
Sobrecargas Função Pública Split(ByVal ParamArray
separator() As Char) As String()
A cadeia de caracteres é tratada como uma sequência de campos separados pelos caracteres na matriz separator. O resultado é uma matriz desses campos
Sobrecarga da Função Pública Substring(
ByVal startIndex As Integer, ByVal length As Integer)
As String
Uma substring da string atual, começando na posição startIndex e contendo length caracteres
Sobrecarga Função Pública ToLower()
Como String
converte a cadeia atual para minúsculas
Sobrecargas Função Pública ToUpper()
Como String
converte a cadeia atual em maiúsculas
Sobrecarga da função pública Trim()
Como String
remove os espaços à esquerda e à direita da string atual

Uma string em C pode ser considerada uma matriz de caracteres. Assim

  • C.Chars(i) é o i-ésimo caractere de C
  • C.Length é o número de caracteres em C

Considere o seguinte exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
 
Module test
    Sub Main()
        Dim uneChaine As String = "l'oiseau vole au-dessus des nuages"
        affiche("uneChaine=" + uneChaine)
        affiche("uneChaine.Length=" & uneChaine.Length)
        affiche("chaine[10]=" + uneChaine.Chars(10))
        affiche("uneChaine.IndexOf(""vole"")=" & uneChaine.IndexOf("vole"))
        affiche("uneChaine.IndexOf(""x"")=" & uneChaine.IndexOf("x"))
        affiche("uneChaine.LastIndexOf('a')=" & uneChaine.LastIndexOf("a"c))
        affiche("uneChaine.LastIndexOf('x')=" & uneChaine.LastIndexOf("x"c))
        affiche("uneChaine.Substring(4,7)=" + uneChaine.Substring(4, 7))
        affiche("uneChaine.ToUpper()=" + uneChaine.ToUpper())
        affiche("uneChaine.ToLower()=" + uneChaine.ToLower())
        affiche("uneChaine.Replace('a','A')=" + uneChaine.Replace("a"c, "A"c))
        Dim champs As String() = uneChaine.Split(Nothing)
        Dim i As Integer
        For i = 0 To champs.Length - 1
            affiche("champs[" & i & "]=[" & champs(i) & "]")
        Next i
        affiche("Join("":"",champs)=" + System.String.Join(":", champs))
        affiche("(""  abc  "").Trim()=[" + "  abc  ".Trim() + "]")
    End Sub
 
    ' poster
    Sub affiche(ByVal msg As [String])
        ' poster msg
        Console.Out.WriteLine(msg)
    End Sub
End Module

A execução produz os seguintes resultados:

dos>vbc string1.vb

dos>string1
uneChaine=l'bird flies above the clouds
uneChaine.Length=34
chaine[10]=o
uneChaine.IndexOf("vole")=9
uneChaine.IndexOf("x")=-1
uneChaine.LastIndexOf('a')=30
uneChaine.LastIndexOf('x')=-1
uneChaine.Substring(4,7)=seau vo
uneChaine.ToUpper()=L'OISEAU VOLE ABOVE DES NUAGES
uneChaine.ToLower()=l'bird flies above the clouds
uneChaine.Replace('a','A')=l'oiseAu flies Over the nuAges
champs[0]=[l'bird]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
Join(":",champs)=l'bird:flies:above:clouds
("  abc  ").Trim()=[abc]

Vamos considerar um novo exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
 
Module string2
    Sub Main()
        ' the line to be analyzed
        Dim ligne As String = "un:deux::trois:"
        ' field separators
        Dim séparateurs() As Char = {":"c}
        ' split
        Dim champs As String() = ligne.Split(séparateurs)
        Dim i As Integer
        For i = 0 To champs.Length - 1
            Console.Out.WriteLine(("Champs[" & i & "]=" & champs(i)))
        Next i
        ' join
        Console.Out.WriteLine(("join=[" + System.String.Join(":", champs) + "]"))
    End Sub
End Module

e os resultados da execução:

Champs[0]=un
Champs[1]=deux
Champs[2]=
Champs[3]=trois
Champs[4]=
join=[un:deux::trois:]

O método Split da classe String permite colocar os campos de uma string numa matriz. A definição do método utilizado aqui é a seguinte:

Overloads Public Function Split(ByVal ParamArray separator() As Char) As String()
separator
matriz de caracteres. Estes caracteres representam os caracteres utilizados para separar os campos na cadeia de caracteres. Assim, se a cadeia de caracteres for [campo1, campo2, campo3], podemos utilizar separator=new char() {","c}. Se o separador for uma sequência de espaços, utilizamos separator=nothing.
resultado
matriz de cadeias de caracteres em que cada elemento é um campo da cadeia de caracteres.

O método Join é um método estático da classe String:

Overloads Public Shared Function Join(ByVal separator As String, ByVal value() As String) As String
valor
matriz de cadeias de caracteres
separador
uma cadeia de caracteres que servirá como separador de campos
resultado
uma cadeia de caracteres formada pela concatenação dos elementos da matriz de valores, separados pela cadeia de caracteres separadora.

4.4. A Classe Array

A classe Array implementa uma matriz. No nosso exemplo, utilizaremos as seguintes propriedades e métodos:

Propriedade pública ReadOnly Length como Integer
propriedade - número de elementos na matriz
Sobrecarga Função Pública Partilhada BinarySearch
(ByVal array As Array, ByVal index As Integer,
ByVal length As Integer, ByVal value As Object) As Integer
Método de classe - retorna a posição do valor na matriz ordenada - pesquisa a partir da posição index e com length elementos
Sobrecarga Public Shared Sub Copy(ByVal sourceArray
As Array, ByVal destinationArray As Array,
ByVal length As Integer)
Método de classe - copia os primeiros length elementos de sourceArray para destinationArray - destinationArray é criado especificamente para este fim
Sobrecarga Public Shared Sub Sort(ByVal array As Array)
Método de classe - ordena a matriz - a matriz deve conter um tipo de dados com uma função de ordenação predefinida (cadeias de caracteres, números).

O programa a seguir ilustra a utilização da classe Array:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
 
Module test
    Sub Main()
        ' read table elements typed on keyboard
        Dim terminé As [Boolean] = False
        Dim i As Integer = 0
        Dim éléments1 As Double() = Nothing
        Dim éléments2 As Double() = Nothing
        Dim élément As Double = 0
        Dim réponse As String = Nothing
        Dim erreur As [Boolean] = False
 
        While Not terminé
            ' question
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' reading the answer
            réponse = Console.ReadLine().Trim()
            ' end of input if string empty
            If réponse.Equals("") Then
                Exit While
            End If
            ' input verification
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' if no error
            If Not erreur Then
                ' new table to accommodate the new element
                éléments2 = New Double(i) {}
                ' copy old panel to new panel
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' new table becomes old table
                éléments1 = éléments2
                ' no need for the new panel
                éléments2 = Nothing
                ' insert new element
                éléments1(i) = élément
                ' one more element in the picture
                i += 1
            End If
        End While
        ' unsorted table display
        System.Console.Out.WriteLine("Tableau non trié")
        For i = 0 To éléments1.Length - 1
            Console.Out.WriteLine(("éléments[" & i & "]=" & éléments1(i)))
        Next i
        ' table sorting
        System.Array.Sort(éléments1)
        ' sorted table display
        System.Console.Out.WriteLine("Tableau trié")
        For i = 0 To éléments1.Length - 1
            Console.Out.WriteLine(("éléments[" & i & "]=" & éléments1(i)))
        Next i
        ' Search
        While Not terminé
            ' question
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' reading-checking response
            réponse = Console.ReadLine().Trim()
            ' finished?
            If réponse.Equals("") Then
                Exit While
            End If
            ' check
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' if no error
            If Not erreur Then
                ' search for the element in the sorted array
                i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
                ' Display response
                If i >= 0 Then
                    Console.Out.WriteLine(("Trouvé en position " & i))
                Else
                    Console.Out.WriteLine("Pas dans le tableau")
                End If
            End If
        End While
    End Sub
End Module

A saída no ecrã é a seguinte:

Elément (réel) 0 du tableau (rien pour terminer) : 10,4
Elément (réel) 1 du tableau (rien pour terminer) : 5,2
Elément (réel) 2 du tableau (rien pour terminer) : 8,7
Elément (réel) 3 du tableau (rien pour terminer) : 3,6
Elément (réel) 4 du tableau (rien pour terminer) :
Tableau non trié
éléments[0]=10,4
éléments[1]=5,2
éléments[2]=8,7
éléments[3]=3,6
Tableau trié
éléments[0]=3,6
éléments[1]=5,2
éléments[2]=8,7
éléments[3]=10,4
Elément cherché (rien pour arrêter) : 8,7
Trouvé en position 2
Elément cherché (rien pour arrêter) : 11
Pas dans le tableau
Elément cherché (rien pour arrêter) : a
Saisie incorrecte, recommencez
Elément cherché (rien pour arrêter) :

A primeira parte do programa constrói uma matriz a partir de dados numéricos introduzidos através do teclado. A matriz não pode ser predefinida, uma vez que não sabemos quantos elementos o utilizador irá introduzir. Trabalhamos, portanto, com duas matrizes, elements1 e elements2.


                ' nouveau tableau pour accueillir le nouvel élément
                éléments2 = New Double(i) {}
                ' copie ancien tableau vers nouveau tableau
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' nouveau tableau devient ancien tableau
                éléments1 = éléments2
                ' plus besoin du nouveau tableau
                éléments2 = Nothing
                ' insertion nouvel élément
                éléments1(i) = élément
                ' un élémt de plus dans le tableau
                i += 1

A matriz elements1 contém os valores atualmente introduzidos. Quando o utilizador adiciona um novo valor, criamos uma matriz elements2 com mais um elemento do que a elements1, copiamos o conteúdo da elements1 para a elements2 (Array.Copy), definimos a elements1 para apontar para a elements2 e, por fim, adicionamos o novo elemento à elements1. Este é um processo complexo que pode ser simplificado utilizando uma matriz de tamanho variável (ArrayList) em vez de uma matriz de tamanho fixo (Array).

A matriz é ordenada utilizando o método Array.Sort. Este método pode ser chamado com vários parâmetros que especificam as regras de ordenação. Sem parâmetros, a ordenação ascendente é realizada por predefinição. Por fim, o método Array.BinarySearch permite procurar um elemento numa matriz ordenada.

4.5. A Classe ArrayList

A classe ArrayList permite implementar matrizes de tamanho variável durante a execução do programa, o que a classe Array anterior não permite. Aqui estão algumas das propriedades e métodos comuns:

Public Sub New()
cria uma lista vazia
Propriedade Pública Overridable ReadOnly Count
As Integer  Implementa ICollection.Count
número de elementos na coleção
Função pública substituível Add(ByVal valor
As Object) As Integer Implements IList.Add
Adiciona o objeto value ao final da coleção
Sub pública substituível Clear()
Implementa IList.Clear
limpa a lista
Sobrecarga Função pública substituível
IndexOf(ByVal value As Object) As Integer
Implementa IList.IndexOf
índice do objeto value na lista ou -1 se não existir
Sobrecarga Função Pública Sobrescritível
IndexOf(ByVal value As Object, ByVal startIndex
As Integer) As Integer
Igual ao anterior, mas começando no elemento startIndex
Sobrecargas Função Pública Sobrescritível
LastIndexOf(ByVal value As Object) As Integer
Igual ao anterior, mas devolve o índice da última ocorrência de value na lista
Sobrecarga Função Pública Sobrescritível
LastIndexOf(ByVal value As Object, ByVal startIndex As Integer) As Integer
Igual ao anterior, mas começando a partir do elemento em startIndex
Public Overridable Sub Remove(ByVal obj As Object)
Implementa IList.Remove
Remove o objeto obj, caso este exista na lista
Sub pública substituível RemoveAt(ByVal index As Integer)
Implementa IList.RemoveAt
remove o elemento no índice da lista
Sobrecarga Função pública substituível
BinarySearch(ByVal value As Object) As Integer
Retorna a posição do objeto value na lista, ou -1 se não for encontrado. A lista deve estar ordenada
Sobrecarga da função pública substituível Sort()
Ordena a lista. A lista deve conter objetos com uma relação de ordenação predefinida (cadeias de caracteres, números)
Sobrecargas Public Overridable Sub
Sort(ByVal comparer As IComparer)
ordena a lista de acordo com a ordem estabelecida pela função comparadora

Vamos rever o exemplo utilizando objetos Array e aplicá-lo a objetos ArrayList:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
 
Module test
    Sub Main()
        ' read table elements typed on keyboard
        Dim terminé As [Boolean] = False
        Dim i As Integer = 0
        Dim éléments As New ArrayList
        Dim élément As Double = 0
        Dim réponse As String = Nothing
        Dim erreur As [Boolean] = False
 
        While Not terminé
            ' question
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' reading the answer
            réponse = Console.ReadLine().Trim()
            ' end of input if string empty
            If réponse.Equals("") Then
                Exit While
            End If
            ' input verification
            Try
                élément = Double.Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' if no error
            If Not erreur Then
                ' one more element in the picture
                éléments.Add(élément)
            End If
        End While
        ' unsorted table display
        System.Console.Out.WriteLine("Tableau non trié")
        For i = 0 To éléments.Count - 1
            Console.Out.WriteLine(("éléments[" & i & "]=" & éléments(i).ToString))
        Next i        ' table sorting
        éléments.Sort()
        ' sorted table display
        System.Console.Out.WriteLine("Tableau trié")
        For i = 0 To éléments.Count - 1
            Console.Out.WriteLine(("éléments[" & i & "]=" & éléments(i).ToString))
        Next i
        ' Search
        While Not terminé
            ' question
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' reading-checking response
            réponse = Console.ReadLine().Trim()
            ' finished?
            If réponse.Equals("") Then
                Exit While
            End If
            ' check
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' if no error
            If Not erreur Then
                ' search for the element in the sorted array
                i = éléments.BinarySearch(élément)
                ' Display response
                If i >= 0 Then
                    Console.Out.WriteLine(("Trouvé en position " & i))
                Else
                    Console.Out.WriteLine("Pas dans le tableau")
                End If
            End If
        End While
    End Sub
End Module

Os resultados da execução são os seguintes:

Elément (réel) 0 du tableau (rien pour terminer) : 10,4
Elément (réel) 0 du tableau (rien pour terminer) : 5,2
Elément (réel) 0 du tableau (rien pour terminer) : a
Saisie incorrecte, recommencez
Elément (réel) 0 du tableau (rien pour terminer) : 3,7
Elément (réel) 0 du tableau (rien pour terminer) : 15
Elément (réel) 0 du tableau (rien pour terminer) :
Tableau non trié
éléments[0]=10,4
éléments[1]=5,2
éléments[2]=3,7
éléments[3]=15
Tableau trié
éléments[0]=3,7
éléments[1]=5,2
éléments[2]=10,4
éléments[3]=15
Elément cherché (rien pour arrêter) : a
Saisie incorrecte, recommencez
Elément cherché (rien pour arrêter) : 15
Trouvé en position 3
Elément cherché (rien pour arrêter) : 1
Pas dans le tableau
Elément cherché (rien pour arrêter) :

4.6. A classe Hashtable

A classe Hashtable permite implementar um dicionário. Um dicionário pode ser visto como uma matriz de duas colunas:

As chaves são únicas; ou seja, não podem existir duas chaves idênticas. Os principais métodos e propriedades da classe Hashtable são os seguintes:

Public Sub New()
cria um dicionário vazio
Public Overridable Sub Add(ByVal key As
Object, ByVal value As Object)
Implementa IDictionary.Add
adiciona uma entrada (chave, valor) ao dicionário, em que chave e valor são referências a objetos.
Public Overridable Sub Remove
(ByVal chave As Object) Implements IDictionary.Remove
remove a entrada com chave=chave do dicionário
Sub pública substituível Clear()
Implementa IDictionary.Clear
limpa o dicionário
Função pública substituível ContainsKey
(ByVal key As Object) As Boolean
Retorna true se a chave key estiver no dicionário.
Função pública substituível
ContainsValue(ByVal value As Object) As Boolean
Retorna true se o valor value estiver no dicionário.
Propriedade pública, substituível e de leitura apenas
Count As Integer  Implementa ICollection.Count
propriedade: número de elementos no dicionário (chave, valor)
Propriedade pública, substituível e somente leitura
Keys como ICollection implementa IDictionary.Keys
propriedade: coleção de chaves do dicionário
Propriedade pública, substituível e de leitura apenas
Valores como ICollection implementa IDictionary.Values
propriedade: coleção de valores do dicionário
Propriedade pública substituível por padrão
Item(ByVal key As Object) As Object  Implementa IDictionary.Item
propriedade indexada: permite recuperar ou definir o valor associado a uma chave

Considere o seguinte programa de exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
 
Module test
    Sub Main()
        Dim liste() As [String] = {"jean:20", "paul:18", "mélanie:10", "violette:15"}
        Dim i As Integer
        Dim champs As [String]() = Nothing
        Dim séparateurs() As Char = {":"c}
        ' filling the dictionary
        Dim dico As New Hashtable
        For i = 0 To liste.Length - 1
            champs = liste(i).Split(séparateurs)
            dico.Add(champs(0), champs(1))
        Next i
        ' number of elements in the dictionary
        Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
        ' kEY LIST
        Console.Out.WriteLine("[Liste des clés]")
        Dim clés As IEnumerator = dico.Keys.GetEnumerator()
        While clés.MoveNext()
            Console.Out.WriteLine(clés.Current)
        End While
        ' list of values
        Console.Out.WriteLine("[Liste des valeurs]")
        Dim valeurs As IEnumerator = dico.Values.GetEnumerator()
        While valeurs.MoveNext()
            Console.Out.WriteLine(valeurs.Current)
        End While
        ' list of keys & values
        Console.Out.WriteLine("[Liste des clés & valeurs]")
        clés.Reset()
        While clés.MoveNext()
            Console.Out.WriteLine(("clé=" & clés.Current.ToString & " valeur=" & dico(clés.Current).ToString))
        End While
        ' delete the "paul" key
        Console.Out.WriteLine("[Suppression d'une clé]")
        dico.Remove("paul")
        ' list of keys & values
        Console.Out.WriteLine("[Liste des clés & valeurs]")
        clés = dico.Keys.GetEnumerator()
        While clés.MoveNext()
            Console.Out.WriteLine(("clé=" & clés.Current.ToString & " valeur=" & dico(clés.Current).ToString))
        End While
 
        ' dictionary search
        Dim nomCherché As [String] = Nothing
        Console.Out.Write("Nom recherché (rien pour arrêter) : ")
        nomCherché = Console.ReadLine().Trim()
        Dim value As [Object] = Nothing
        While Not nomCherché.Equals("")
            If dico.ContainsKey(nomCherché) Then
                value = dico(nomCherché)
                Console.Out.WriteLine((nomCherché + "," + CType(value, [String])))
            Else
                Console.Out.WriteLine(("Nom " + nomCherché + " inconnu"))
            End If
            ' next search
            Console.Out.Write("Nom recherché (rien pour arrêter) : ")
            nomCherché = Console.ReadLine().Trim()
        End While
    End Sub
End Module

Os resultados da execução são os seguintes:

Le dictionnaire a 4 éléments
[Liste des clés]
mélanie
paul
violette
jean
[Liste des valeurs]
10
18
15
20
[Liste des clés & valeurs]
clé=mélanie valeur=10
clé=paul valeur=18
clé=violette valeur=15
clé=jean valeur=20
[Suppression d'une clé]
[Liste des clés & valeurs]
clé=mélanie valeur=10
clé=violette valeur=15
clé=jean valeur=20
Nom recherché (rien pour arrêter) : paul
Nom paul inconnu
Nom recherché (rien pour arrêter) : mélanie
mélanie,10
Nom recherché (rien pour arrêter) :

O programa também utiliza um objeto IEnumerator para percorrer as coleções de chaves e valores no dicionário do tipo ICollection (ver as propriedades Chaves e Valores acima). Uma coleção é um conjunto de objetos que pode ser percorrido. A interface ICollection é definida da seguinte forma:

Image

A propriedade Count permite-nos determinar o número de elementos na coleção. A interface ICollection deriva da interface IEnumerable:

Image

Esta interface tem apenas um método, GetEnumerator, que nos permite obter um objeto do tipo IEnumerator:

Image

O método GetEnumerator() de uma ICollection permite-nos percorrer a coleção utilizando os seguintes métodos:

Avançar
avança para o elemento seguinte na coleção. Retorna true se este elemento existir, false caso contrário. O primeiro MoveNext avança para o primeiro elemento. O elemento «atual» da coleção fica então disponível na propriedade Current do enumerador
Current
propriedade: elemento atual da coleção
Reset
redefine o iterador para o início da coleção, ou seja, antes do primeiro elemento.

A estrutura para iterar sobre os elementos de uma coleção C (ICollection) é, portanto, a seguinte:

' define collection
dim C as ICollection C=...
' get an enumerator of this collection
dim itérateur as IEnumerator=C.GetEnumerator();
' browse the collection with this enumerator
while(itérateur.MoveNext())
    ' we have a current element
    ' operate itérateur.Current
end while

4.7. A classe StreamReader

A classe StreamReader permite-lhe ler o conteúdo de um ficheiro. Aqui estão algumas das suas propriedades e métodos:

Public Sub New(ByVal path As String)
abre um fluxo a partir do caminho do ficheiro. É lançada uma exceção se o ficheiro não existir
Substitui Public Sub Close()
fecha o fluxo
Sobrescreve a função pública ReadLine() como String
Lê uma linha do fluxo aberto
Sobrescreve a função pública ReadToEnd() como String
Lê o resto do fluxo a partir da posição atual

Eis um exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.IO
 
Module test
    Sub Main()
        Dim ligne As String = Nothing
        Dim fluxInfos As StreamReader = Nothing
        ' read file content
        Try
            fluxInfos = New StreamReader("infos.txt")
            ligne = fluxInfos.ReadLine()
            While Not (ligne Is Nothing)
                System.Console.Out.WriteLine(ligne)
                ligne = fluxInfos.ReadLine()
            End While
        Catch e As Exception
            System.Console.Error.WriteLine("L'erreur suivante s'est produite : " & e.ToString)
        Finally
            Try
                fluxInfos.Close()
            Catch
            End Try
        End Try
    End Sub
End Module

e os seus resultados de execução:

dos>more infos.txt
12620:0:0
13190:0,05:631
15640:0,1:1290,5
24740:0,15:2072,5
31810:0,2:3309,5
39970:0,25:4900
48360:0,3:6898,5
55790:0,35:9316,5
92970:0,4:12106
127860:0,45:16754,5
151250:0,5:23147,5
172040:0,55:30710
195000:0,6:39312
0:0,65:49062

dos>file1
12620:0:0
13190:0,05:631
15640:0,1:1290,5
24740:0,15:2072,5
31810:0,2:3309,5
39970:0,25:4900
48360:0,3:6898,5
55790:0,35:9316,5
92970:0,4:12106
127860:0,45:16754,5
151250:0,5:23147,5
172040:0,55:30710
195000:0,6:39312
0:0,65:49062

4.8. A classe StreamWriter

A classe StreamWriter permite-lhe escrever num ficheiro. Aqui estão algumas das suas propriedades e métodos:

Public Sub New(ByVal path As String)
abre um fluxo de escrita a partir do caminho do ficheiro. É lançada uma exceção se o fluxo não puder ser criado
Public Overridable Property AutoFlush
As Boolean
Se definido como true, a gravação no fluxo ignora o buffer; caso contrário, a gravação no fluxo não é imediata: os dados são primeiro gravados num buffer e, em seguida, no fluxo quando o buffer estiver cheio. Por predefinição, é utilizado o modo com buffer. É adequado para fluxos de ficheiros, mas geralmente não para fluxos de rede.
Propriedade pública substituível NewLine
Como String
Para definir ou recuperar o caractere de fim de linha utilizado pelo método WriteLine
Substitui o método público Close()
Fecha o fluxo
Sobrecarga Public Overridable Sub
WriteLine(ByVal value As String)
escreve uma linha no fluxo de escrita
Substitui Sub Flush()
esvazia o buffer para o fluxo

Considere o seguinte exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.IO
 
Module test
    Sub Main()
        Dim ligne As String = Nothing        ' one line of text
        Dim fluxInfos As StreamWriter = Nothing        ' the text file
        Try
            ' text file creation
            fluxInfos = New StreamWriter("infos.txt")
            ' read line typed on keyboard
            Console.Out.Write("ligne (rien pour arrêter) : ")
            ligne = Console.In.ReadLine().Trim()
            ' loop as long as the line entered is not empty
            While ligne <> ""
                ' write line to text file
                fluxInfos.WriteLine(ligne)
                ' read new line on keyboard
                Console.Out.Write("ligne (rien pour arrêter) : ")
                ligne = Console.In.ReadLine().Trim()
            End While
        Catch e As Exception
            System.Console.Error.WriteLine("L'erreur suivante s'est produite : " & e.ToString)
        Finally
            ' close file
            Try
                fluxInfos.Close()
            Catch
            End Try
        End Try
    End Sub
End Module

e os resultados da execução:

dos>file2
ligne (rien pour arrêter) : ligne1
ligne (rien pour arrêter) : ligne2
ligne (rien pour arrêter) : ligne3
ligne (rien pour arrêter) :

dos>more infos.txt
ligne1
ligne2
ligne3

4.9. A classe Regex

A classe Regex permite a utilização de expressões regulares. Estas são utilizadas para validar o formato de uma cadeia de caracteres. Por exemplo, pode verificar se uma cadeia de caracteres que representa uma data está no formato dd/mm/aa. Para tal, utiliza-se um padrão e compara-se a cadeia de caracteres com esse padrão. Neste exemplo, d, m e y devem ser dígitos. O padrão para um formato de data válido é, portanto, "\d\d/\d\d/\d\d", onde o símbolo \d representa um dígito. Os símbolos que podem ser utilizados num padrão são os seguintes (documentação da Microsoft):

 
Descrição
\
Designa o caractere seguinte como 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 "\(" corresponde a "(".
^
Corresponde ao início da entrada.
$
Corresponde ao fim da entrada.
*
Corresponde ao caractere anterior zero ou mais vezes. Assim, «zo*» corresponde a «z» ou «zoo».
+
Corresponde ao caractere anterior uma ou mais vezes. Assim, «zo+» corresponde a «zoo», mas não a «z».
?
Corresponde ao caractere anterior zero ou uma vez. Por exemplo, "a?ve?" corresponde a "ve" em "lever".
.
Corresponde a qualquer caractere único, exceto o caractere de nova linha.

(padrão)
Procura o padrão e armazena a correspondência. A subcadeia correspondente pode ser recuperada da coleção Matches resultante utilizando Item [0]...[n]. Para corresponder a 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 ocorrências do caractere. Por exemplo, "o{2}" não corresponde a "o" em "Bob", mas corresponde aos dois primeiros "o"s em "fooooot".

{n,}
n é um número inteiro não negativo. Corresponde a pelo menos n ocorrências do caractere. Por exemplo, "o{2,}" não corresponde a "o" em "Bob", mas corresponde a todos os "o"s em "fooooot". "o{1,}" é equivalente a "o+" e "o{0,}" é equivalente 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 ocorrências do caractere. Por exemplo, «o{1,3}» corresponde aos primeiros três «o» em «foooooot» e «o{0,1}» é equivalente a «o?».

[xyz]
Conjunto de caracteres. Corresponde a qualquer um dos caracteres especificados. Por exemplo, "[abc]" corresponde a "a" em "plat".

[^xyz]
Conjunto de caracteres negativo. Corresponde a qualquer caractere não listado. Por exemplo, "[^abc]" corresponde a "p" em "plat".

[a-z]
Intervalo de caracteres. Corresponde a qualquer caractere no intervalo especificado. Por exemplo, "[a-z]" corresponde a qualquer caractere alfabético minúsculo entre "a" e "z".

[^m-z]
Intervalo de caracteres negativo. Corresponde a qualquer caractere que não esteja no intervalo especificado. Por exemplo, "[^m-z]" corresponde a qualquer caractere que não esteja entre "m" e "z".
\b
Corresponde a um limite de palavra, ou seja, a posição entre uma palavra e um espaço. Por exemplo, "er\b" corresponde a "er" em "lever", mas não a "er" em "verb".
\B
Corresponde a um limite que não representa uma palavra. "en*t\B" corresponde a "ent" em "bien entendu".
\d
Corresponde a um caractere que representa um dígito. Equivalente a [0-9].
\D
Corresponde a um caractere que não seja um dígito. Equivalente a [^0-9].
\f
Corresponde a um caractere de quebra de linha.
\n
Corresponde a um caractere de nova linha.
\r
Equivalente a um caractere de retorno de carro.
\s
Corresponde a qualquer espaço em branco, incluindo espaço, tabulação, quebra de página, etc. Equivalente a "[ \f\n\r\t\v]".
\S
Corresponde a qualquer caractere que não seja um espaço em branco. Equivalente a "[^ \f\n\r\t\v]".
\t
Corresponde a um caractere de tabulação.
\v
Corresponde a um caractere de tabulação vertical.
\w
Corresponde a qualquer caractere que represente uma palavra, incluindo o sublinhado. Equivalente a "[A-Za-z0-9_]".
\W
Corresponde a qualquer caractere que não represente uma palavra. Equivalente a "[^A-Za-z0-9_]".

\num
Corresponde a num, onde num é um número inteiro positivo. Refere-se a correspondências armazenadas. Por exemplo, "(.)\1" corresponde a dois caracteres idênticos consecutivos.

\n
Corresponde a n, onde n é um valor de escape octal. Os valores de escape octais devem consistir em 1, 2 ou 3 dígitos. Por exemplo, "\11" e "\011" correspondem ambos a um caractere de tabulação. "\0011" é equivalente a "\001" e "1". Os valores de escape octais não devem exceder 256. Se excederem, apenas os dois primeiros dígitos são tidos em conta na expressão. Permite que os códigos ASCII sejam utilizados em expressões regulares.

\xn
Corresponde a n, onde n é um valor de escape hexadecimal. Os valores de escape hexadecimais devem consistir em dois dígitos. Por exemplo, "\x41" corresponde a "A". "\x041" é equivalente a "\x04" e "1". Permite a utilização de códigos ASCII em expressões regulares.

Um elemento num padrão pode aparecer uma ou várias vezes. Vejamos alguns exemplos envolvendo o símbolo \d, que representa um único dígito:

padrão
significado
\d
um dígito
\d?
0 ou 1 dígito
\d*
0 ou mais dígitos
\d+
1 ou mais dígitos
\d{2}
2 dígitos
\d{3,}
pelo menos 3 dígitos
\d{5,7}
entre 5 e 7 dígitos

Agora, imaginemos um modelo capaz de descrever o formato esperado para uma cadeia de caracteres:

cadeia de caracteres alvo
padrão
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 inteiro sem sinal
\d+
uma sequência de espaços, que pode estar vazia
\s*
um inteiro sem sinal que pode ser precedido ou seguido por espaços
\s*\d+\s*
um inteiro que pode ser assinado e precedido ou seguido por espaços
\s*[+|-]?\s*\d+\s*
um número real sem sinal que pode ser precedido ou seguido por espaços
\s*\d+(.\d*)?\s*
um número real que pode ser assinado e precedido ou seguido por espaços
\s*[+|]?\s*\d+(.\d*)?\s*
uma cadeia de caracteres que contenha a palavra «just»
\bjuste\b
  

Pode especificar onde procurar o padrão na cadeia de caracteres:

padrão
significado
^padrão
o padrão inicia a cadeia
padrão$
o padrão termina a cadeia
^padrão$
o padrão inicia e termina a cadeia
padrão
o padrão é procurado em qualquer parte da cadeia, começando pelo início.
cadeia de pesquisa
padrão
uma cadeia que termine com um ponto de exclamação
!$
uma cadeia que termina com um ponto
\.$
uma sequência que começa com //
^//
uma cadeia de caracteres composta por uma única palavra, opcionalmente seguida ou precedida por espaços
^\s*\w+\s*$
uma cadeia composta por duas palavras, opcionalmente seguida ou precedida por espaços
^\s*\w+\s*\w+\s*$
uma cadeia de caracteres que contém a palavra secret
\bsecret\b

Os subpadrões de um padrão podem ser «extraídos». Assim, não só podemos verificar se uma cadeia corresponde a um determinado padrão, como também podemos extrair dessa cadeia os elementos correspondentes aos subpadrões do padrão que foram colocados entre parênteses. Por exemplo, se estivermos a analisar uma cadeia de caracteres que contenha uma data no formato dd/mm/aa e também quisermos extrair os elementos dd, mm e aa dessa data, usaríamos o padrão (\d\d)/(\d\d)/(\d\d).

4.9.1. Verificar se uma string corresponde a um determinado padrão

Um objeto Regex é construído da seguinte forma:

Public Sub New(ByVal pattern As String)

O construtor cria um objeto de «expressão regular» a partir de um padrão passado como parâmetro (pattern). Depois de construído o padrão de expressão regular, este pode ser comparado com cadeias de caracteres utilizando o método IsMatch:

Overloads Public Function IsMatch(ByVal input As String) As Boolean

IsMatch retorna true se a cadeia de caracteres de entrada corresponder ao padrão de expressão regular. Aqui está um exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
 
Module regex1
 
    Sub Main()
        ' a regular expression template
        Dim modèle1 As String = "^\s*\d+\s*$"
        Dim regex1 As New Regex(modèle1)
        ' compare a copy with the model
        Dim exemplaire1 As String = "  123  "
        If regex1.IsMatch(exemplaire1) Then
            affiche(("[" + exemplaire1 + "] correspond au modèle [" + modèle1 + "]"))
        Else
            affiche(("[" + exemplaire1 + "] ne correspond pas au modèle [" + modèle1 + "]"))
        End If
        Dim exemplaire2 As String = "  123a  "
        If regex1.IsMatch(exemplaire2) Then
            affiche(("[" + exemplaire2 + "] correspond au modèle [" + modèle1 + "]"))
        Else
            affiche(("[" + exemplaire2 + "] ne correspond pas au modèle [" + modèle1 + "]"))
        End If
    End Sub
 
    ' poster 
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

e os resultados da execução:

dos>vbc /r:system.dll regex1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573

dos>regex1
[  123  ] correspond au modèle [^\s*\d+\s*$]
[  123a  ] ne correspond pas au modèle [^\s*\d+\s*$]

4.9.2. Encontrar todos os elementos numa cadeia de caracteres que correspondam a um padrão

O método Matches

Overloads Public Function Matches(ByVal input As String) As MatchCollection

retorna uma coleção de elementos da cadeia de caracteres de entrada que correspondem ao padrão, conforme mostrado no exemplo a seguir:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
 
Module regex2
    Sub Main()
        ' several occurrences of the model in the copy
        Dim modèle2 As String = "\d+"
        Dim regex2 As New Regex(modèle2)        '
        Dim exemplaire3 As String = "  123  456  789 "
        Dim résultats As MatchCollection = regex2.Matches(exemplaire3)
        affiche(("Modèle=[" + modèle2 + "],exemplaire=[" + exemplaire3 + "]"))
        affiche(("Il y a " & résultats.Count & " occurrences du modèle dans l'exemplaire "))
        Dim i As Integer
        For i = 0 To résultats.Count - 1
            affiche((résultats(i).Value & " en position " & résultats(i).Index))
        Next i
    End Sub
 
    'poster
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

A classe MatchCollection possui uma propriedade Count, que corresponde ao número de elementos na coleção. Se results for um objeto MatchCollection, results(i) é o i-ésimo elemento desta coleção e é do tipo Match. No nosso exemplo, results é o conjunto de elementos na string example3 que correspondem ao padrão pattern2, e results(i) é um desses elementos. A classe Match possui duas propriedades relevantes neste contexto:

  • Value: o valor do objeto Match, ou seja, o elemento que corresponde ao padrão
  • Index: a posição onde o elemento foi encontrado na string pesquisada

Os resultados da execução do programa anterior:

dos>vbc /r:system.dll regex2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4p our Microsoft (R) .NET Framework version 1.1.4322.573

dos>regex2
Modèle=[\d+],exemplaire=[  123  456  789 ]
Il y a 3 occurrences du modèle dans l'exemplaire
123 en position 2
456 en position 7
789 en position 12

4.9.3. Extrair partes de um padrão

É possível «extrair» subconjuntos de um padrão. Assim, não só podemos verificar se uma cadeia corresponde a um determinado padrão, como também podemos extrair dessa cadeia os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Assim, se estivermos a analisar uma cadeia de caracteres que contenha uma data no formato dd/mm/aa e também quisermos extrair os elementos dd, mm e aa dessa data, utilizaremos o padrão (\d\d)/(\d\d)/(\d\d). Vejamos o seguinte exemplo:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
 
Module regex2
    Sub Main()
        ' capture elements in the model
        Dim modèle3 As String = "(\d\d):(\d\d):(\d\d)"
        Dim regex3 As New Regex(modèle3)
        Dim exemplaire4 As String = "Il est 18:05:49"
        ' model checking
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' the copy corresponds to the model
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' display groups
            Dim i As Integer
            For i = 0 To résultat.Groups.Count - 1
                affiche(("groupes[" & i & "]=[" & résultat.Groups(i).Value & "] en position " & résultat.Groups(i).Index))
            Next i
        Else
            ' the copy does not correspond to the model
            affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
        End If
    End Sub
 
    'poster
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

A execução deste programa produz os seguintes resultados:

dos>vbc /r:system.dll regex3.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4

dos>regex3
L'exemplaire [Il est 18:05:49] correspond au modèle [(\d\d):(\d\d):(\d\d)]
groupes[0]=[18:05:49] en position 7
groupes[1]=[18] en position 7
groupes[2]=[05] en position 10
groupes[3]=[49] en position 13

A nova funcionalidade encontra-se no seguinte trecho de código:


        ' model checking
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' the copy corresponds to the model
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' display groups
            Dim i As Integer
            For i = 0 To résultat.Groups.Count - 1
                affiche(("groupes[" & i & "]=[" & résultat.Groups(i).Value & "] en position " & résultat.Groups(i).Index))
            Next i
        Else

A cadeia de caracteres example4 é comparada com o padrão regex3 utilizando o método Match. Isto devolve um objeto Match, tal como descrito anteriormente. Aqui, utilizamos duas novas propriedades desta classe:

  • Success: indica se houve uma correspondência
  • Groups: uma coleção em que
    • Groups[0] corresponde à parte da string que corresponde ao padrão
    • Groups[i] (i>=1) corresponde ao i-ésimo grupo de parênteses

Se o resultado for do tipo Match, results.Groups é do tipo GroupCollection e results.Groups[i] é do tipo Group. A classe Group tem duas propriedades que usamos aqui:

  • Value: o valor do objeto Group que contém o elemento correspondente ao conteúdo de um parêntese
  • Index: a posição onde o elemento foi encontrado na string analisada

4.9.4. Um programa de treino

Encontrar a expressão regular que nos permite verificar se uma cadeia corresponde a um determinado padrão pode, por vezes, ser um verdadeiro desafio. O programa seguinte permite-lhe praticar. Pede um padrão e uma cadeia e, em seguida, indica se a cadeia corresponde ou não ao padrão.


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic
 
Module regex4
    Sub Main()
        ' a regular expression template
        Dim modèle, chaine As String
        Dim regex As Regex = Nothing
        Dim résultats As MatchCollection
        ' the user is asked for models and samples to compare with this one
        Dim terminé1 As Boolean = False
        Do While Not terminé1
            Dim erreur As Boolean = True
            Do While Not terminé1 And erreur
                ' the model is requested
                Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
                modèle = Console.In.ReadLine()
                ' finished?
                If modèle.Trim().ToLower() = "fin" Then
                    terminé1 = True
                Else
                    ' we create the regular expression
                    Try
                        regex = New Regex(modèle)
                        erreur = False
                    Catch ex As Exception
                        Console.Error.WriteLine(("Erreur : " + ex.Message))
                    End Try
                End If
            Loop
            ' finished?
            If terminé1 Then Exit Sub
            ' the user is asked for the specimens to be compared with the model
            Dim terminé2 As Boolean = False
            Do While Not terminé2
                Console.Out.Write(("Tapez la chaîne à comparer au modèle [" + modèle + "] ou fin pour arrêter :"))
                chaine = Console.In.ReadLine()
                ' finished?
                If chaine.Trim().ToLower() = "fin" Then
                    terminé2 = True
                Else
                    ' we make the comparison
                    résultats = regex.Matches(chaine)
                    ' success?
                    If résultats.Count = 0 Then
                        Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
                    Else
                        ' the elements corresponding to the model are displayed
                        Dim i As Integer
                        For i = 0 To résultats.Count - 1
                            Console.Out.WriteLine(("J'ai trouvé la correspondance [" & résultats(i).Value & "] en position " & résultats(i).Index))
                            ' sub-elements
                            If résultats(i).Groups.Count <> 1 Then
                                Dim j As Integer
                                For j = 1 To (résultats(i).Groups.Count) - 1
                                    Console.Out.WriteLine((ControlChars.Tab & "sous-élément [" & résultats(i).Groups(j).Value & "] en position " & résultats(i).Groups(j).Index))
                                Next j
                            End If
                        Next i
                    End If
                End If
            Loop
        Loop
    End Sub
 
    'poster
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

Aqui está um exemplo de execução:

Tapez le modèle à tester ou fin pour arrêter :\d+
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :123 456 789
J'ai trouvé la correspondance [123] en position 0
J'ai trouvé la correspondance [456] en position 4
J'ai trouvé la correspondance [789] en position 8
Tapez la chaîne à comparer au modèle [\d+] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :(\d\d):(\d\d)
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :14:15 abcd 17:18 xyzt
J'ai trouvé la correspondance [14:15] en position 0
        sous-élément [14] en position 0
        sous-élément [15] en position 3
J'ai trouvé la correspondance [17:18] en position 11
        sous-élément [17] en position 11
        sous-élément [18] en position 14
Tapez la chaîne à comparer au modèle [(\d\d):(\d\d)] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :^\s*\d+\s*$
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :  1456
J'ai trouvé la correspondance [  1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*\d+\s*$] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :^\s*(\d+)\s*$
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :1456
J'ai trouvé la correspondance [1456] en position 0
        sous-élément [1456] en position 0
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :abcd 1
456
Je n'ai pas trouvé de correspondances
Tapez la chaîne à comparer au modèle [^\s*(\d+)\s*$] ou fin pour arrêter :fin

Tapez le modèle à tester ou fin pour arrêter :fin

4.9.5. O método Split

Já nos deparámos com este método na classe String:

Overloads Public Function Split(ByVal ParamArray separator() As Char) As String()

A string é tratada como uma sequência de campos separados pelos caracteres da matriz [separator]. O resultado é uma matriz desses campos.

O separador de campos na cadeia de caracteres é um dos caracteres da matriz separator. O método Split da classe Regex permite-nos especificar o separador com base num padrão:

Overloads Public Function Split(ByVal input As String) As String()

A cadeia [input] é dividida em campos, que são separados por um separador que corresponde ao padrão do objeto Regex atual. Suponha, por exemplo, que tenhamos linhas num ficheiro de texto com o formato campo1, campo2, ..., campoN. Os campos são separados por uma vírgula, mas esta pode ser precedida ou seguida por espaços. O método Split da classe String não é, portanto, adequado. O método RegEx fornece a solução. Se line for a linha lida, os campos podem ser obtidos por

dim champs() as string=new Regex("s*,\s*").Split(ligne)

conforme mostrado no exemplo a seguir:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Text.RegularExpressions
 
Module regex5
    Sub Main()
        ' a line
        Dim ligne As String = "abc  , def  , ghi"
        ' a model
        Dim modèle As New Regex("\s*,\s*")
        ' decomposition of line into fields
        Dim champs As String() = modèle.Split(ligne)
        ' display
        Dim i As Integer
        For i = 0 To champs.Length - 1
            Console.Out.WriteLine(("champs[" & i & "]=[" & champs(i) & "]"))
        Next i
    End Sub
End Module

Resultados da execução:

dos>vbc /r:system.dll regex5.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4

dos>regex5
champs[0]=[abc]
champs[1]=[def]
champs[2]=[ghi]

4.10. As classes BinaryReader e BinaryWriter

As classes BinaryReader e BinaryWriter são utilizadas para ler e escrever ficheiros binários. Considere a seguinte aplicação. Pretendemos escrever um programa que seria chamado da seguinte forma:

// syntaxe pg texte bin
// on lit un fichier texte (texte) et on range son contenu dans un
// fichier binaire
// le fichier texte a des lignes de la forme nom : age
// qu'on rangera dans une structure string, int

O ficheiro de texto tem o seguinte conteúdo:

paul : 10
helene : 15
jacques : 11
sylvain : 12

O programa é o seguinte:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
 
' BinaryWriter()
 
Module bw1
    ' syntax pg text bin
    ' read a text file (text) and store its contents in a
    ' binary file
    ' the text file has lines of the form name: age
    ' which will be stored in a string structure, int
 
    Sub Main(ByVal arguments() As String)
        ' you need 2 arguments
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg texte binaire")
            Environment.Exit(1)
        End If
        ' open text file in read mode
        Dim input As StreamReader = Nothing
        Try
            input = New StreamReader(arguments(0))
        Catch ex As Exception
            Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(0) & "(" & ex.Message & ")")
            Environment.Exit(2)
        End Try
        ' open binary file for writing
        Dim output As BinaryWriter = Nothing
        Try
            output = New BinaryWriter(New FileStream(arguments(1), FileMode.Create, FileAccess.Write))
        Catch ex As Exception
            Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(1) & "(" & ex.Message & ")")
            Environment.Exit(3)
        End Try
        ' read text file - write binary file
        ' text file line
        Dim ligne As String
        ' line field separator
        Dim séparateur As New Regex("\s*:\s*")
        ' the age model
        Dim modAge As New Regex("\s*\d+\s*")
        Dim numLigne As Integer = 0
        Dim traitementFini As Boolean
        Dim champs As String()
        ligne = input.ReadLine()
        While Not (ligne Is Nothing)
            traitementFini = False
            ' empty line?
            If ligne.Trim() = "" Then
                traitementFini = True
            End If
            ' one more line
            If Not traitementFini Then
                numLigne += 1
                ' one line name: age
                champs = séparateur.Split(ligne)
                ' we need 2 fields
                If champs.Length <> 2 Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
                    ' next line
                    traitementFini = True
                End If
            End If
            If Not traitementFini Then
                ' the second field must be an integer >=0
                If Not modAge.IsMatch(champs(1)) Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
                    ' next line
                    traitementFini = True
                End If
                ' write data to the binary file
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))
            End If
            'next line
            ligne = input.ReadLine()
        End While
        ' closing files
        input.Close()
        output.Close()
    End Sub
End Module

Vamos analisar mais detalhadamente as operações relacionadas com a classe BinaryWriter:

  • O objeto BinaryWriter é aberto pela operação

            output = New BinaryWriter(New FileStream(arguments(1), FileMode.Create, FileAccess.Write))

O argumento do construtor deve ser um fluxo (Stream). Aqui, trata-se de um fluxo criado a partir de um ficheiro (FileStream) para o qual especificamos:

  • (continuação)
    • o nome
    • a operação a realizar, neste caso `FileMode.Create` para criar o ficheiro
    • o tipo de acesso, neste caso FileAccess.Write para acesso de escrita ao ficheiro
  • a operação de gravação

                ' on écrit les données dans le fichier binaire
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))

A classe BinaryWriter possui vários métodos Write sobrecarregados para gravar diferentes tipos de dados simples

  • a operação de fecho do fluxo
        output.Close()

Os resultados da execução anterior serão fornecidos pelo programa a seguir. Este programa também aceita dois argumentos:

    ' syntaxe pg bin texte
    ' on lit un fichier binaire bin et on range son contenu dans un fichier texte (texte)
    ' le fichier binaire a une structure string, int
    ' le fichier texte a des lignes de la forme nom : age

Estamos, portanto, a realizar a operação inversa. Lemos um ficheiro binário para criar um ficheiro de texto. Se o ficheiro de texto resultante for idêntico ao ficheiro original, saberemos que a conversão texto --> binário --> texto foi bem-sucedida. O código é o seguinte:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
 
Module br1
    ' syntax pg bin text
    ' read a binary bin file and store its contents in a text file (text)
    ' the binary file has a structure string, int
    ' the text file has lines of the form name: age
 
    Sub Main(ByVal arguments() As String)
        ' you need 2 arguments
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg binaire texte")
            Environment.Exit(1)
        End If
        ' open binary file for reading
        Dim dataIn As BinaryReader = Nothing
        Try
            dataIn = New BinaryReader(New FileStream(arguments(0), FileMode.Open, FileAccess.Read))
        Catch ex As Exception
            Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(0) & "(" & ex.Message & ")")
            Environment.Exit(2)
        End Try
        ' open text file for writing
        Dim dataOut As StreamWriter = Nothing
        Try
            dataOut = New StreamWriter(arguments(1))
            dataOut.AutoFlush = True
        Catch ex As Exception
            Console.Error.WriteLine("Erreur d'ouverture du fichier " & arguments(1) & "(" & ex.Message & ")")
            Environment.Exit(3)
        End Try
        ' read binary file - write text file
        Dim nom As String        ' name of a person
        Dim age As Integer        ' his age
        ' binary file evaluation loop
        While True
            ' read name
            Try
                nom = dataIn.ReadString()
            Catch
                ' end of file
                Exit Sub
            End Try
            ' age reading
            Try
                age = dataIn.ReadInt32()
            Catch
                Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
                Exit Sub
            End Try
            ' writing to text file
            dataOut.WriteLine(nom & ":" & age)
            System.Console.WriteLine(nom & ":" & age)
        End While
        ' we close everything
        dataIn.Close()
        dataOut.Close()
    End Sub
End Module

Vamos analisar mais detalhadamente as operações relacionadas com a classe BinaryReader:

  • O objeto BinaryReader é aberto pela operação

            dataIn = New BinaryReader(New FileStream(arguments(0), FileMode.Open, FileAccess.Read))

O argumento do construtor deve ser um fluxo (Stream). Aqui, trata-se de um fluxo criado a partir de um ficheiro (FileStream) para o qual especificamos:

  • (continuação)
    • o nome
    • a operação a realizar, neste caso `FileMode.Open` para abrir um ficheiro existente
    • o tipo de acesso, neste caso FileAccess.Read para acesso de leitura ao ficheiro
  • a operação de leitura
                nom = dataIn.ReadString()
                age = dataIn.ReadInt32()

A classe BinaryReader fornece vários métodos ReadXX para ler diferentes tipos de dados simples

  • a operação para fechar o fluxo
        dataIn.Close()

Se executarmos os dois programas em sequência, convertendo o ficheiro «personnes.txt» para «personnes.bin» e, em seguida, «personnes.bin» para «personnes.txt2», obtemos:

dos>more personnes.txt
paul : 10
helene : 15
jacques : 11
sylvain : 12

dos>more personnes.txt2
paul:10
helene:15
jacques:11
sylvain:12

dos>dir
29/04/2002  18:19                   54 personnes.txt
29/04/2002  18:19                   44 personnes.bin
29/04/2002  18:20                   44 personnes.txt2