Skip to content

4. Classes .NET de uso comum

Apresentamos aqui algumas classes da plataforma .NET que são de interesse, mesmo para um iniciante. Mostramos, em primeiro lugar, como obter informações sobre as centenas de classes disponíveis.

4.1. Buscar ajuda com SDK.NET

4.1.1. wincv

Se tiver sido instalado apenas o SDK e não o Visual Studio.NET, será possível utilizar o programa wincv.exe, normalmente localizado na estrutura de diretórios do SDK, por exemplo, C:\Program Files\Microsoft Visual Studio.NET 2003\SDK\v1.1. Ao executar esse utilitário, é exibida a seguinte interface:

Digita-se em (1) o nome da classe desejada. Isso exibe em (2) vários temas possíveis. Escolhe-se o mais adequado e obtém-se o resultado em (3), neste caso, a classe HashTable. Esse método é adequado se soubermos o nome da classe que estamos procurando. Se quisermos explorar a lista de possibilidades oferecidas pela plataforma .NET, pode-se usar o arquivo HTML StartHere.htm, que também está localizado diretamente na pasta de instalação do SSK.Net, por exemplo, C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.

Image

O link .NET Framework SDK Documentação é o que deve ser acessado para obter uma visão geral das classes .NET:

Image

Nesse link, seguiremos o link [Bibliothèque de classes]. Lá, encontramos a lista de todas as classes de .NET:

Image

Vamos seguir, por exemplo, o link System.Collections. Esse espaço de nomes reúne diversas classes que implementam coleções, entre as quais a classe HashTable:

Image

Vamos seguir o link HashTable abaixo:

Image

Chegamos à seguinte página:

Image

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

Lá encontramos o protótipo da classe, bem como exemplos de uso. Vamos acessar o link [Hashtable, membres] abaixo:

Image

Obtemos a descrição completa da classe:

Image

Esse método é o melhor para explorar o SDK e suas classes. A ferramenta WinCV é útil quando já se tem algum conhecimento sobre a classe, mas se esqueceu de alguns de seus membros. O WinCV permite, então, localizar rapidamente a classe e seus membros.

4.2. Buscar ajuda sobre as classes com o VS.NET

Apresentamos aqui algumas orientações para encontrar ajuda com o Visual Studio.NET

4.2.1. Opção Ajuda

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

Image

Aparece a seguinte janela:

Image

Na lista suspensa, é possível selecionar um filtro de ajuda. Aqui, vamos escolher o filtro [Visual Basic].

Image

Há duas ajudas úteis:

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

A ajuda sobre a linguagem VB.NET pode ser acessada por meio de [Visual Studio.NET/Visual Basic et Visual C#/Reference/Visual Basic]:

Image

É exibida a seguinte página de ajuda:

Image

A partir daí, as diferentes subseções permitem que obtenhamos ajuda sobre diversos temas do VB.NET. Preste atenção aos tutoriais do VB.NET:

Image

Para acessar as diferentes classes da plataforma .NET, selecione a ajuda [Visual Studio.NET/.NET Framework].

Image

Vamos nos concentrar, em particular, na seção [Référence/Bibliothèque de classes]:

Image

Suponhamos que estejamos interessados na classe [ArrayList]. Ela está localizada no espaço de nomes [System.Collections]. É importante saber disso; caso contrário, é preferível utilizar o método de pesquisa descrito a seguir. Obtemos a seguinte ajuda:

Image

O link [ArrayList, classe] fornece uma visão geral da classe:

Image

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

Image

4.2.2. Ajuda/Índice

Image

A opção [Aide/index] permite buscar uma ajuda mais específica do que a anterior. Basta digitar a palavra-chave procurada:

Image

A vantagem desse método em relação ao anterior é que não é necessário saber onde se encontra o que se procura no sistema de ajuda. Esse é provavelmente o método preferível quando se faz uma pesquisa direcionada, já que o outro método é mais adequado para explorar tudo o que a ajuda oferece.

4.3. A classe String

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

Public ReadOnly Property Length As Integer
número de caracteres da string
Public Default ReadOnly Property 
Chars(ByVal index As Integer) As Char
propriedade indexada por padrão. [String].Chars(i) é o caractere nº i da string
Public Function EndsWith(ByVal value As String) 
As Boolean
retorna verdadeiro se a string terminar com o valor
Public Function StartsWith(ByVal value As String) 
As Boolean
retorna verdadeiro se a string começar com o valor
Overloads Public Function Equals(ByVal value 
As String) As Boolean
retorna verdadeiro se a string for igual a value
Overloads Public Function IndexOf(ByVal value 
As String) As Integer
retorna a primeira posição da string na string value — a busca começa a partir do caractere nº 0
Overloads Public Function IndexOf(ByVal value 
As String,ByVal startIndex As Integer) As Integer
retorna a primeira posição na string do valor - a busca começa a partir do caractere nº startIndex
Overloads Public Shared Function 
Join(ByVal separator As String,ByVal value() 
As String) As String
método de classe — retorna uma sequência de caracteres, resultado da concatenação dos valores da matriz value com o separador separator
Overloads Public Function Replace(ByVal oldChar 
As Char,ByVal newChar As Char) As String
retorna uma cópia da string atual, na qual o caractere oldChar foi substituído pelo caractere newChar
Overloads Public Function Split(ByVal ParamArray
separator() As Char) As String()
a string é considerada como uma sequência de campos separados pelos caracteres presentes na tabela separator. O resultado é a tabela desses campos
Overloads Public Function Substring(
ByVal startIndex As Integer,ByVal length As Integer) 
As String
subcadeia da cadeia atual que começa na posição startIndex e possui length caracteres
Overloads Public Function ToLower() 
As String
converte a cadeia atual em letras minúsculas
Overloads Public Function ToUpper() 
As String
converte a string atual em maiúsculas
Overloads Public Function Trim() 
As String
remove os espaços no início e no final da string atual

Uma cadeia C pode ser considerada como uma matriz de caracteres. Assim,

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

Consideremos o seguinte exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
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

    ' exibe
    Sub affiche(ByVal msg As [String])
        ' exibe mensagem
        Console.Out.WriteLine(msg)
    End Sub
End Module

A execução produz os seguintes resultados:

dos>vbc string1.vb

dos>string1
uneChaine=l'oiseau vole au-dessus des nuages
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 AU-DESSUS DES NUAGES
uneChaine.ToLower()=l'oiseau vole au-dessus des nuages
uneChaine.Replace('a','A')=l'oiseAu vole Au-dessus des nuAges
champs[0]=[l'oiseau]
champs[1]=[vole]
champs[2]=[au-dessus]
champs[3]=[des]
champs[4]=[nuages]
Join(":",champs)=l'oiseau:vole:au-dessus:des:nuages
("  abc  ").Trim()=[abc]

Vamos considerar um novo exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System

Module string2
    Sub Main()
        ' a linha a ser analisada
        Dim ligne As String = "un:deux::trois:"
        ' separadores de campos
        Dim séparateurs() As Char = {":"c}
        ' divisão
        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
        ' junção
        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 sequência de caracteres em uma 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. Esses caracteres representam os caracteres utilizados para separar os campos da sequência de caracteres. Assim, se a sequência for [champ1, champ2, champ3], poderá-se utilizar separator=new char() {","c}. Se o separador for uma sequência de espaços, utilizar-se-á separator=nothing.
résultat
matriz de cadeias de caracteres em que cada elemento é um campo da cadeia.

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
value
matriz de cadeias de caracteres
separator
uma sequência de caracteres que servirá como separador de campos
résultat
uma sequência de caracteres formada pela concatenação dos elementos da matriz value, separados pela sequência separator.

4.4. A classe Array

A classe Array implementa um array. Utilizaremos, em nosso exemplo, as seguintes propriedades e métodos:

Public ReadOnly Property Length As Integer
propriedade — número de elementos da matriz
Overloads Public Shared Function 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 de value na matriz ordenada array — pesquisa a partir da posição index e com length elementos
Overloads Public Shared Sub Copy(ByVal sourceArray 
As Array,ByVal destinationArray As Array,
ByVal length As Integer)
método de classe — copia os elementos de length de sourceArray para destinationArray destinationArray é criado para a ocasião
Overloads Public Shared Sub Sort(ByVal array As Array)
método de classe — ordena a matriz array — esta deve conter um tipo de dados com uma função de ordenação padrão (cadeias de caracteres, números).

O programa a seguir ilustra o uso da classe Array:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System

Module test
    Sub Main()
        ' leitura dos elementos de uma matriz digitados pelo teclado
        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é
            ' pergunta
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' leitura da resposta
            réponse = Console.ReadLine().Trim()
            ' fim da entrada se a string estiver vazia
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificação da entrada
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se não houver erro
            If Not erreur Then
                ' nova tabela para receber o novo elemento
                éléments2 = New Double(i) {}
                ' cópia da matriz antiga para a nova matriz
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' a nova tabela passa a ser a tabela antiga
                éléments1 = éléments2
                ' não há mais necessidade da nova tabela
                éléments2 = Nothing
                ' inserção de um novo elemento
                éléments1(i) = élément
                ' mais um elemento na tabela
                i += 1
            End If
        End While
        ' exibição da tabela sem ordenação
        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
        ' classificação da tabela
        System.Array.Sort(éléments1)
        ' exibição da tabela ordenada
        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
        ' Pesquisa
        While Not terminé
            ' pergunta
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' Leitura e verificação da resposta
            réponse = Console.ReadLine().Trim()
            ' Concluído?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificação
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se não houver erro
            If Not erreur Then
                ' procura-se o elemento na tabela ordenada
                i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
                ' Exibição da resposta
                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 na tela são os seguintes:

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 cria uma matriz a partir de dados numéricos digitados pelo teclado. O tamanho da matriz não pode ser definido antecipadamente, pois não se sabe quantos elementos o usuário irá digitar. Trabalha-se, portanto, com duas matrizes: éléments1 e éléments2.


                ' nova matriz para receber o novo elemento
                éléments2 = New Double(i) {}
                ' cópia da tabela antiga para a nova tabela
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' a nova tabela passa a ser a tabela antiga
                éléments1 = éléments2
                ' não há mais necessidade da nova tabela
                éléments2 = Nothing
                ' inserção de um novo elemento
                éléments1(i) = élément
                ' mais um elemento na tabela
                i += 1

A matriz éléments1 contém os valores atualmente inseridos. Quando o usuário adiciona um novo valor, cria-se uma matriz éléments2 com um elemento a mais do que éléments1, copia-se o conteúdo de éléments1 para éléments2 (Array.Copy), faz-se com que éléments1 “aponte” para éléments2 e, por fim, adiciona-se o novo elemento a éléments1. Trata-se de um processo complexo que pode ser simplificado se, em vez de usar uma matriz de tamanho fixo (Array), utilizarmos uma matriz de tamanho variável (ArrayList).

A matriz é classificada com o método Array.Sort. Esse método pode ser chamado com diferentes parâmetros que especificam as regras de classificação. Sem parâmetros, é realizada, por padrão, uma classificação em ordem crescente. Por fim, o método Array.BinarySearch permite procurar um elemento em uma matriz classificada.

4.5. A classe ArrayList

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

Public Sub New()
cria uma lista vazia
Public Overridable ReadOnly Property Count 
As Integer  Implements ICollection.Count
número de elementos da coleção
Public Overridable Function Add(ByVal value 
As Object) As Integer Implements IList.Add
adiciona o objeto value ao final da coleção
Public Overridable Sub Clear() 
Implements IList.Clear
apaga a lista
Overloads Public Overridable Function 
IndexOf(ByVal value As Object) As Integer 
Implements IList.IndexOf
índice do objeto value na lista ou -1 caso ele não exista
Overloads Public Overridable Function 
IndexOf(ByVal value As Object, ByVal startIndex 
As Integer) As Integer
O mesmo, mas buscando a partir do elemento nº startIndex
Overloads Public Overridable Function 
LastIndexOf(ByVal value As Object) As Integer
O mesmo, mas retorna o índice da última ocorrência de “value” na lista
Overloads Public Overridable Function 
LastIndexOf(ByVal value As Object, ByVal startIndex As Integer) As Integer
O mesmo, mas buscando a partir do elemento nº startIndex
Public Overridable Sub Remove( ByVal obj As Object)
Implements IList.Remove
remove o objeto obj, caso ele exista na lista
Public Overridable Sub RemoveAt(ByVal index As Integer) 
Implements IList.RemoveAt
remove o elemento index da lista
Overloads Public Overridable Function 
BinarySearch(ByVal value As Object) As Integer
retorna a posição do objeto `value` na lista ou -1 caso ele não esteja presente. A lista deve estar ordenada
Overloads Public Overridable Sub Sort()
ordena a lista. Ela deve conter objetos com uma relação de ordem predefinida (cadeias de caracteres, números)
Overloads Public Overridable Sub 
Sort(ByVal comparer As IComparer)
ordena a lista de acordo com a relação de ordem estabelecida pela função comparar

Vamos retomar o exemplo tratado com objetos do tipo Array e processá-lo com objetos do tipo ArrayList:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections

Module test
    Sub Main()
        ' leitura dos elementos de uma tabela digitados pelo teclado
        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é
            ' pergunta
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' leitura da resposta
            réponse = Console.ReadLine().Trim()
            ' fim da entrada se a string estiver vazia
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificação da entrada
            Try
                élément = Double.Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se não houver erro
            If Not erreur Then
                ' mais um elemento na tabela
                éléments.Add(élément)
            End If
        End While
        ' exibição da tabela não ordenada
        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        ' tri du tableau
        éléments.Sort()
        ' exibição da tabela ordenada
        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
        ' Pesquisa
        While Not terminé
            ' pergunta
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' Leitura e verificação da resposta
            réponse = Console.ReadLine().Trim()
            ' terminou?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificação
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se não houver erro
            If Not erreur Then
                ' procura-se o elemento na tabela ordenada
                i = éléments.BinarySearch(élément)
                ' Exibição da resposta
                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. Pode-se considerar um dicionário como uma tabela com duas colunas:

As chaves são únicas, c.a.d, ou seja, não pode haver 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) 
Implements IDictionary.Add
adiciona uma linha (chave, valor) ao dicionário, em que chave e valor são referências a objetos.
Public Overridable Sub Remove
(ByVal key As Object) Implements IDictionary.Remove
remove do dicionário a linha com chave=key
Public Overridable Sub Clear() 
Implements IDictionary.Clear
esvazia o dicionário
Public Overridable Function ContainsKey
(ByVal key As Object) As Boolean
retorna verdadeiro (true) se a chave key pertencer ao dicionário.
Public Overridable Function 
ContainsValue(ByVal value As Object) As Boolean
retorna verdadeiro (true) se o valor value pertencer ao dicionário.
Public Overridable ReadOnly Property 
Count As Integer  Implements ICollection.Count
propriedade: número de elementos do dicionário (chave, valor)
Public Overridable ReadOnly Property 
Keys As ICollection Implements IDictionary.Keys
propriedade: coleção das chaves do dicionário
Public Overridable ReadOnly Property 
Values As ICollection Implements IDictionary.Values
propriedade: coleção de valores do dicionário
Public Overridable Default Property 
Item(ByVal key As Object) As Object  Implements IDictionary.Item
propriedade indexada: permite consultar ou definir o valor associado a uma chave

Consideremos o seguinte programa de exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
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}
        ' preenchimento do dicionário
        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
        ' número de elementos no dicionário
        Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
        ' lista de chaves
        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
        ' lista de valores
        Console.Out.WriteLine("[Liste des valeurs]")
        Dim valeurs As IEnumerator = dico.Values.GetEnumerator()
        While valeurs.MoveNext()
            Console.Out.WriteLine(valeurs.Current)
        End While
        ' lista de chaves e valores
        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
        ' a chave “paul” é excluída
        Console.Out.WriteLine("[Suppression d'une clé]")
        dico.Remove("paul")
        ' lista de chaves e valores
        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

        ' pesquisa no dicionário
        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
            ' próxima pesquisa
            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 do dicionário do tipo ICollection (veja acima as propriedades Keys e Values). Uma coleção é um conjunto de objetos que pode ser percorrido. A interface ICollection é definida da seguinte forma:

Image

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

Image

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

Image

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

MoveNext
posiciona no próximo elemento da coleção. Retorna verdadeiro (true) se esse elemento existir, falso (false) caso contrário. O primeiro MoveNext posiciona no 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
reposiciona o enumerador no início da coleção, c.a.d, antes do primeiro elemento.

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

' definir a coleção
dim C as ICollection C=...
' obter um enumerador dessa coleção
dim itérateur as IEnumerator=C.GetEnumerator();
' percorrer a coleção com esse enumerador
while(itérateur.MoveNext())
    ' temos um elemento atual
     ' processar itérateur.Current
end while

4.7. A classe StreamReader

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

Public Sub New(ByVal path As String)
abre um fluxo a partir do arquivo path. É lançada uma exceção se o arquivo não existir
Overrides Public Sub Close()
fecha o fluxo
Overrides Public Function ReadLine() As String
lê uma linha do fluxo aberto
Overrides Public Function ReadToEnd() As String
lê o restante do fluxo a partir da posição atual

Veja um exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.IO

Module test
    Sub Main()
        Dim ligne As String = Nothing
        Dim fluxInfos As StreamReader = Nothing
        ' leitura do conteúdo do arquivo
        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 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 gravar em um arquivo. Aqui estão algumas de suas propriedades e métodos:

Public Sub New(ByVal path As String)
abre um fluxo de gravação a partir do arquivo path. Uma exceção é lançada se ele não puder ser criado
Public Overridable Property AutoFlush 
As Boolean
se for igual a verdadeiro, a gravação no fluxo não passa por um buffer; caso contrário, a gravação no fluxo não é imediata: primeiro ocorre a gravação em um buffer e, em seguida, no fluxo quando o buffer estiver cheio. Por padrão, é utilizado o modo com buffer. Ele é adequado para fluxos de arquivo, mas geralmente não para fluxos de rede.
Public Overridable Property NewLine 
As String
para definir ou verificar o caractere de fim de linha a ser usado pelo método WriteLine
Overrides Public Sub Close()
fecha o fluxo
Overloads Public Overridable Sub 
WriteLine(ByVal value As String)
grava uma linha no fluxo de gravação
Overrides Public Sub Flush()
grava o buffer no fluxo

Consideremos o seguinte exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.IO

Module test
    Sub Main()
        Dim ligne As String = Nothing        ' une ligne de texte
        Dim fluxInfos As StreamWriter = Nothing        ' le fichier texte
        Try
            ' criação do arquivo de texto
            fluxInfos = New StreamWriter("infos.txt")
            ' leitura da linha digitada no teclado
            Console.Out.Write("ligne (rien pour arrêter) : ")
            ligne = Console.In.ReadLine().Trim()
            ' loop enquanto a linha digitada não estiver vazia
            While ligne <> ""
                ' gravação da linha no arquivo de texto
                fluxInfos.WriteLine(ligne)
                ' leitura de uma nova linha digitada no teclado
                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
            ' fechamento do arquivo
            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 o uso de expressões regulares. Elas permitem verificar o formato de uma sequência de caracteres. Assim, é possível verificar se uma sequência que representa uma data está, de fato, no formato dd/mm/aa. Para isso, utiliza-se um modelo e compara-se a sequência com esse modelo. Portanto, neste exemplo, j, m e a devem ser números. O modelo de um formato de data válido é, portanto, “\d\d/\d\d/\d\d”, onde o símbolo \d representa um algarismo. Os símbolos que podem ser utilizados em um modelo são os seguintes (documentação da Microsoft):

 
Descrição
\ 
Marca o caractere seguinte como 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 a “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.

(modèle) 
Pesquisa o modèle e armazena a correspondência. A subcadeia correspondente pode ser extraída da coleção Matches obtida, por meio do Item [0]...[n]. Para encontrar correspondências com caracteres entre parênteses ( ), use "\(" 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 caractere. 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 caractere. 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 pelo menos n e, no máximo, m vezes o caractere. 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 na 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 esteja na série especificada. Por exemplo, “[^m-z]” corresponde a qualquer caractere que não esteja entre “m” e “z”.
\b 
Corresponde a um limite que representa uma palavra; em outras palavras, à 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 caractere que representa um algarismo. É equivalente a [0-9].
\D 
Corresponde a um caractere que não representa um algarismo. É equivalente a [^0-9].
\f 
Corresponde a um caractere de quebra de página.
\n 
Corresponde a um caractere de nova linha.
\r 
Corresponde 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 de espaço nã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 e inclua um 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 às 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 conter 1, 2 ou 3 dígitos. Por exemplo, “\11” e “\011” correspondem ambos a um caractere de tabulação. "\0011" equivale a "\001" e "1". Os valores de escape octais não devem exceder 256. Se isso ocorrer, apenas os dois primeiros dígitos serão considerados na expressão. Permite usar os códigos ASCII em expressões regulares.

\xn
Corresponde a n, onde n é um valor de escape hexadecimal. Os valores de escape hexadecimais devem conter obrigatoriamente dois dígitos. Por exemplo, “\x41” corresponde a “A”. “\x041” equivale a “\x04” e “1”. Permite usar os códigos ASCII em expressões regulares.

Um elemento em um modelo pode estar presente uma ou mais vezes. Vejamos alguns exemplos relacionados ao símbolo \d, que representa um dígito:

modelo
significado
\d
um número
\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

Imaginemos agora o modelo capaz de descrever o formato esperado para uma sequência de caracteres:

sequência procurada
modelo
une date au format jj/mm/aa
\d{2}/\d{2}/\d{2}
une heure au format hh:mm:ss
\d{2}:\d{2}:\d{2}
un nombre entier non signé
\d+
un suite d'espaces éventuellement vide
\s*
un nombre entier non signé qui peut être précédé ou suivi d'espaces
\s*\d+\s*
un nombre entier qui peut être signé et précédé ou suivi d'espaces
\s*[+|-]?\s*\d+\s*
un nombre réel non signé qui peut être précédé ou suivi d'espaces
\s*\d+(.\d*)?\s*
un nombre réel qui peut être signé et précédé ou suivi d'espaces
\s*[+|]?\s*\d+(.\d*)?\s*
une chaîne contenant le mot juste
\bjusto\b
  

É possível especificar onde procurar o padrão na sequência:

padrão
significado
^modèle
o modelo inicia a sequência
modèle$
o modelo termina a sequência
^modèle$
o modelo inicia e encerra a sequência
modèle
o padrão é procurado em toda a sequência, começando pelo início dela.
cadeia procurada
padrão
une chaîne se terminant par un point d'exclamation
!$
une chaîne se terminant par un point
\.$
une chaîne commençant par la séquence //
^//
une chaîne ne comportant qu'un mot éventuellement suivi ou précédé d'espaces
^\s*\w+\s*$
une chaîne ne comportant deux mot éventuellement suivis ou précédés d'espaces
^\s*\w+\s*\w+\s*$
une chaîne contenant le mot secret
\bsecret\b

Os subconjuntos de um padrão podem ser “recuperados”. Assim, não só é possível verificar se uma sequência corresponde a um padrão específico, como também é possível recuperar nessa sequência os elementos correspondentes aos subconjuntos do padrão que foram colocados entre parênteses. Assim, se analisarmos uma sequência de caracteres contendo uma data dd/mm/aa e quisermos, além disso, extrair os elementos dd, mm e aa dessa data, utilizaremos o modelo (\d\d)/(\d\d)/(\d\d).

4.9.1. Verificar se uma sequência corresponde a um determinado modelo

Um objeto do tipo Regex é construído da seguinte maneira:

Public Sub New(ByVal pattern As String)

O construtor cria um objeto “expressão regular” a partir de um padrão passado como parâmetro (pattern). Uma vez construída a expressão regular modelo, é possível compará-la a cadeias de caracteres com o método IsMatch:

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

IsMatch retorna verdadeiro se a string de entrada corresponder ao padrão da expressão regular. Veja um exemplo:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex1

    Sub Main()
        ' uma expressão regular modelo
        Dim modèle1 As String = "^\s*\d+\s*$"
        Dim regex1 As New Regex(modèle1)
        ' comparar uma instância com o modelo
        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

    ' exibe 
    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 de uma sequência 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 string input que correspondem ao padrão, conforme mostrado no exemplo a seguir:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' várias ocorrências do modelo na instância
        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

    'exibe
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

A classe MatchCollection possui uma propriedade Count, que representa o número de elementos da coleção. Se résultats é um objeto MatchCollection, résultats(i) é o elemento i dessa coleção e é do tipo Match. Em nosso exemplo, résultats é o conjunto de elementos da cadeia exemplaire3 correspondentes ao modelo modèle2, e résultats(i) é um desses elementos. A classe Match possui duas propriedades que nos interessam aqui:

  • Value: o valor do objeto Match, ou seja, o elemento correspondente ao modelo
  • Index: a posição em que o elemento foi encontrado na sequência explorada

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. Recuperar partes de um modelo

Subconjuntos de um modelo podem ser “recuperados”. Assim, não só é possível verificar se uma sequência corresponde a um modelo específico, como também é possível recuperar nessa sequência os elementos correspondentes aos subconjuntos do modelo que foram colocados entre parênteses. Assim, se analisarmos uma sequência de caracteres contendo uma data dd/mm/aa e quisermos, além disso, extrair os elementos dd, mm e aa dessa data, utilizaremos o modelo (\d\d)/(\d\d)/(\d\d). Vejamos o exemplo a seguir:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' captura de elementos no modelo
        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"
        ' verificação do modelo
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' a cópia corresponde ao modelo
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' exibição dos grupos
            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
            ' o exemplar não corresponde ao modelo
            affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
        End If
    End Sub

    'exibe
    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 novidade está na seguinte parte do código:


        ' verificação do modelo
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' o exemplar corresponde ao modelo
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' exibindo os grupos
            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 string exemplaire4 é comparada ao modelo regex3 por meio do método Match. Esse método retorna um objeto Match já apresentado. Utilizamos aqui duas novas propriedades dessa classe:

  • Success: indica se houve correspondência
  • Groups: coleção na qual
    • Groups[0] corresponde à parte da string que corresponde ao modelo
    • Groups[i] (i>=1) corresponde ao grupo de parênteses nº i

Se o resultado for do tipo Match, résultats.Groups é do tipo GroupCollection e résultats.Groups[i] é do tipo Group. A classe Group possui duas propriedades que utilizamos aqui:

  • Value: o valor do objeto Group, que é o elemento correspondente ao conteúdo de um parêntese
  • Index: a posição em que 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 de fato a um determinado modelo é, às vezes, um verdadeiro desafio. O programa a seguir permite praticar. Ele solicita um modelo e uma cadeia e, em seguida, indica se a cadeia corresponde ou não ao modelo.


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic

Module regex4
    Sub Main()
        ' uma expressão regular modelo
        Dim modèle, chaine As String
        Dim regex As Regex = Nothing
        Dim résultats As MatchCollection
        ' solicita-se ao usuário os modelos e exemplares a serem comparados com este
        Dim terminé1 As Boolean = False
        Do While Not terminé1
            Dim erreur As Boolean = True
            Do While Not terminé1 And erreur
                ' solicita-se o modelo
                Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
                modèle = Console.In.ReadLine()
                ' Concluído?
                If modèle.Trim().ToLower() = "fin" Then
                    terminé1 = True
                Else
                    ' cria-se a expressão regular
                    Try
                        regex = New Regex(modèle)
                        erreur = False
                    Catch ex As Exception
                        Console.Error.WriteLine(("Erreur : " + ex.Message))
                    End Try
                End If
            Loop
            ' Concluído?
            If terminé1 Then Exit Sub
            ' solicita-se ao usuário os exemplares a serem comparados com o modelo
            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()
                ' concluído?
                If chaine.Trim().ToLower() = "fin" Then
                    terminé2 = True
                Else
                    ' faz-se a comparação
                    résultats = regex.Matches(chaine)
                    ' sucesso?
                    If résultats.Count = 0 Then
                        Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
                    Else
                        ' são exibidos os elementos que correspondem ao modelo
                        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))
                            ' subelementos
                            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

    'exibe
    Sub affiche(ByVal msg As String)
        Console.Out.WriteLine(msg)
    End Sub
End Module

Veja 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 deparamos com esse método na classe String:

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

A string é vista como uma sequência de campos separados pelos caracteres presentes na tabela [separator]. O resultado é a tabela desses campos.

O separador de campos da cadeia é, neste caso, um dos caracteres da tabela separator. O método Split da classe Regex permite-nos definir o separador com base em um padrão:

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

A cadeia [input] é decomposta em campos, sendo estes separados por um separador correspondente ao modelo do objeto Regex atual. Suponhamos, por exemplo, que tenhamos em um arquivo de texto linhas da forma campo1, campo2, ..., campo n. 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 é adequado nesse caso. O método RegEx oferece a solução. Se linha for a linha lida, os campos poderão ser obtidos por

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

conforme mostra o exemplo a seguir:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Text.RegularExpressions

Module regex5
    Sub Main()
        ' uma linha
        Dim ligne As String = "abc  , def  , ghi"
        ' um modelo
        Dim modèle As New Regex("\s*,\s*")
        ' decomposição da linha em campos
        Dim champs As String() = modèle.Split(ligne)
        ' exibição
        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 servem para ler e gravar arquivos binários. Consideremos o seguinte exemplo. Queremos escrever um programa que seria chamado da seguinte forma:

// sintaxe pg texto bin
// lê-se um arquivo de texto (texto) e armazena-se seu conteúdo em um
// arquivo binário
// o arquivo de texto contém linhas no formato nome : idade
// que serão armazenadas em uma estrutura string, int

O arquivo de texto tem o seguinte conteúdo:

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

O programa é o seguinte:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

' BinaryWriter()

Module bw1
    ' sintaxe pg texto bin
    ' lê-se um arquivo de texto (texto) e seu conteúdo é armazenado em um
    ' arquivo binário
    ' o arquivo de texto contém linhas no formato nome : idade
    ' que serão armazenadas em uma estrutura string, int

    Sub Main(ByVal arguments() As String)
        ' são necessários 2 argumentos
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg texte binaire")
            Environment.Exit(1)
        End If
        ' abertura do arquivo de texto para leitura
        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
        ' abertura do arquivo binário para gravação
        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
        ' leitura do arquivo de texto - gravação do arquivo binário
        ' linha do arquivo de texto
        Dim ligne As String
        ' separador dos campos da linha
        Dim séparateur As New Regex("\s*:\s*")
        ' o formato da idade
        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
            ' linha vazia?
            If ligne.Trim() = "" Then
                traitementFini = True
            End If
            ' mais uma linha
            If Not traitementFini Then
                numLigne += 1
                ' uma linha nome: idade
                champs = séparateur.Split(ligne)
                ' precisamos de 2 campos
                If champs.Length <> 2 Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
                    ' linha seguinte
                    traitementFini = True
                End If
            End If
            If Not traitementFini Then
                ' o segundo campo deve ser um número inteiro >=0
                If Not modAge.IsMatch(champs(1)) Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
                    ' linha seguinte
                    traitementFini = True
                End If
                ' gravamos os dados no arquivo binário
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))
            End If
            'linha seguinte
            ligne = input.ReadLine()
        End While
        ' fechamento dos arquivos
        input.Close()
        output.Close()
    End Sub
End Module

Vamos nos deter nas operações relacionadas à 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 construído a partir de um arquivo (FileStream), para o qual se fornece:

  • (continuação)
    • o nome
    • a operação a ser realizada, neste caso FileMode.Create para criar o arquivo
    • o tipo de acesso, neste caso FileAccess.Write para acesso em gravação ao arquivo
  • a operação de gravação

                 ' os dados são gravados no arquivo binário
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))

A classe BinaryWriter possui diferentes métodos Write sobrecarregados para gravar os diversos tipos de dados simples

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

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

     ' sintaxe pg bin texto
     ' lê-se um arquivo binário bin e seu conteúdo é armazenado em um arquivo de texto (texto)
     ' o arquivo binário possui uma estrutura string, int
     ' o arquivo de texto contém linhas no formato nome : idade

Portanto, realizamos a operação inversa. Lemos um arquivo binário para criar um arquivo de texto. Se o arquivo de texto gerado for idêntico ao arquivo original, saberemos que a conversão texto → binário → texto ocorreu corretamente. O código é o seguinte:


' opções
Option Strict On
Option Explicit On 

' espaços de nomes
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

Module br1
    ' sintaxe pg bin texto
    ' lê-se um arquivo binário bin e seu conteúdo é armazenado em um arquivo de texto (texto)
    ' o arquivo binário tem uma estrutura string, int
    ' o arquivo de texto contém linhas no formato nome : idade

    Sub Main(ByVal arguments() As String)
        ' são necessários 2 argumentos
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg binaire texte")
            Environment.Exit(1)
        End If
        ' abertura do arquivo binário para leitura
        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
        ' abertura do arquivo de texto para gravação
        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
        ' leitura do arquivo binário – gravação do arquivo de texto
        Dim nom As String        ' nom d'une personne
        Dim age As Integer        ' son âge
        ' ciclo de processamento do arquivo binário
        While True
            ' leitura do nome
            Try
                nom = dataIn.ReadString()
            Catch
                ' fim do arquivo
                Exit Sub
            End Try
            ' leitura da idade
            Try
                age = dataIn.ReadInt32()
            Catch
                Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
                Exit Sub
            End Try
            ' gravação no arquivo de texto
            dataOut.WriteLine(nom & ":" & age)
            System.Console.WriteLine(nom & ":" & age)
        End While
        ' fechando tudo
        dataIn.Close()
        dataOut.Close()
    End Sub
End Module

Vamos nos deter nas operações relacionadas à 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 construído a partir de um arquivo (FileStream), para o qual fornecemos:

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

A classe BinaryReader dispõe de diferentes métodos ReadXX para ler os diferentes tipos de dados simples

  • a operação de fechamento do fluxo
        dataIn.Close()

Se executarmos os dois programas em sequência, transformando personnes.txt em personnes.bin e, em seguida, personnes.bin em 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