Skip to content

4. Classi .NET di uso comune

Qui presentiamo alcune classi della piattaforma .NET che possono risultare interessanti anche per un principiante. Mostriamo innanzitutto come ottenere informazioni sulle centinaia di classi disponibili.

4.1. Cercare assistenza con SDK.NET

4.1.1. wincv

Se è stato installato solo SDK e non Visual Studio.NET, sarà possibile utilizzare il programma wincv.exe, che si trova solitamente nella struttura di directory dell’SDK, ad esempio C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1. Quando si avvia questa utility, viene visualizzata la seguente interfaccia:

Si digita in (1) il nome della classe desiderata. In questo modo vengono visualizzati in (2) vari temi possibili. Si sceglie quello adatto e si ottiene il risultato in (3), in questo caso la classe HashTable. Questo metodo è adatto se si conosce il nome della classe che si sta cercando. Se si desidera esplorare l'elenco delle possibilità offerte dalla piattaforma .NET, si potrà utilizzare il file HTML StartHere.htm, anch’esso situato direttamente nella cartella di installazione di SSK.Net, ad esempio C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.

Image

Il collegamento .NET Framework SDK Documentazione è quello da seguire per avere una panoramica delle classi .NET:

Image

A questo punto, seguiremo il link [Bibliothèque de classes]. Qui si trova l'elenco di tutte le classi di .NET:

Image

Seguiamo ad esempio il link System.Collections. Questo spazio dei nomi raggruppa diverse classi che implementano collezioni, tra cui la classe HashTable:

Image

Seguiamo il collegamento HashTable riportato di seguito:

Image

Otteniamo la seguente pagina:

Image

Si noti, qui sotto, la posizione del cursore. Esso indica un link che permette di specificare il linguaggio desiderato, in questo caso Visual Basic.

Qui si trovano il prototipo della classe e alcuni esempi di utilizzo. Seguiamo il link [Hashtable, membres] riportato di seguito:

Image

Si ottiene la descrizione completa della classe:

Image

Questo metodo è il migliore per scoprire SDK e le sue classi. Lo strumento WinCV risulta utile quando si conosce già un po’ la classe e si sono dimenticati alcuni dei suoi membri. WinCV consente quindi di ritrovare rapidamente la classe e i suoi membri.

4.2. Cercare aiuto sulle classi con VS.NET

Di seguito forniamo alcune indicazioni per trovare assistenza con Visual Studio.NET

4.2.1. Opzione Aiuto

Selezioniamo l’opzione [?] dal menu.

Image

Si apre la seguente finestra:

Image

Nel menu a tendina è possibile selezionare un filtro di aiuto. In questo caso, sceglieremo il filtro [Visual Basic].

Image

Sono disponibili due guide utili:

  • la guida sul linguaggio VB.NET stesso (sintassi)
  • la guida sui classes.NET utilizzabili dal linguaggio VB.NET

La guida al linguaggio VB.NET è accessibile tramite [Visual Studio.NET/Visual Basic et Visual C#/Reference/Visual Basic]:

Image

Si ottiene la seguente pagina di guida:

Image

Da qui, le diverse sottosezioni ci consentono di ottenere assistenza su vari argomenti relativi a VB.NET. Presteremo particolare attenzione alle guide pratiche di VB.NET:

Image

Per accedere alle diverse classi della piattaforma .NET, selezioneremo la guida [Visual Studio.NET/.NET Framework].

Image

Ci si concentrerà in particolare sulla sezione [Référence/Bibliothèque de classes]:

Image

Supponiamo di essere interessati alla classe [ArrayList]. Essa si trova nello spazio dei nomi [System.Collections]. È importante saperlo, altrimenti si preferirà il metodo di ricerca illustrato di seguito. Si ottiene la seguente guida:

Image

Il link [ArrayList, classe] fornisce una panoramica della classe:

Image

Questo tipo di pagina è disponibile per tutte le classi. Fornisce una sintesi della classe con alcuni esempi. Per una descrizione dei membri della classe, seguire il link [ArrayList, membres]:

Image

4.2.2. Aiuto/Indice

Image

L'opzione [Aide/index] consente di cercare un aiuto più mirato rispetto a quello precedente. È sufficiente digitare la parola chiave desiderata:

Image

Il vantaggio di questo metodo rispetto al precedente è che non è necessario sapere dove si trova ciò che si sta cercando nel sistema di aiuto. È probabilmente il metodo da preferire quando si effettua una ricerca mirata, mentre l’altro metodo è più adatto per scoprire tutto ciò che offre la guida.

4.3. La classe String

La classe String presenta numerose proprietà e metodi. Eccone alcuni:

Public ReadOnly Property Length As Integer
numero di caratteri della stringa
Public Default ReadOnly Property 
Chars(ByVal index As Integer) As Char
proprietà indicizzata per impostazione predefinita. [String].Chars(i) è il carattere n. i della stringa
Public Function EndsWith(ByVal value As String) 
As Boolean
restituisce vero se la stringa termina con il valore
Public Function StartsWith(ByVal value As String) 
As Boolean
restituisce vero se la stringa inizia con il valore
Overloads Public Function Equals(ByVal value 
As String) As Boolean
restituisce vero se la stringa è uguale a value
Overloads Public Function IndexOf(ByVal value 
As String) As Integer
restituisce la prima posizione della stringa "value" nella stringa - la ricerca inizia dal carattere n. 0
Overloads Public Function IndexOf(ByVal value 
As String,ByVal startIndex As Integer) As Integer
restituisce la prima posizione nella stringa del valore - la ricerca inizia dal carattere n. startIndex
Overloads Public Shared Function 
Join(ByVal separator As String,ByVal value() 
As String) As String
metodo di classe - restituisce una stringa di caratteri, risultato della concatenazione dei valori dell'array value con il separatore separator
Overloads Public Function Replace(ByVal oldChar 
As Char,ByVal newChar As Char) As String
restituisce una stringa copia della stringa corrente in cui il carattere oldChar è stato sostituito dal carattere newChar
Overloads Public Function Split(ByVal ParamArray
separator() As Char) As String()
la stringa viene considerata come una sequenza di campi separati dai caratteri presenti nell'array separator. Il risultato è l'array di questi campi
Overloads Public Function Substring(
ByVal startIndex As Integer,ByVal length As Integer) 
As String
sottostringa della stringa corrente che inizia alla posizione startIndex e ha una lunghezza di length caratteri
Overloads Public Function ToLower() 
As String
converte la stringa corrente in minuscolo
Overloads Public Function ToUpper() 
As String
converte la stringa corrente in maiuscolo
Overloads Public Function Trim() 
As String
rimuove gli spazi iniziali e finali dalla stringa corrente

Una stringa C può essere considerata come un array di caratteri. Pertanto

  • C.Chars(i) è il carattere i di C
  • C.Length è il numero di caratteri di C

Consideriamo il seguente esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
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

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

L'esecuzione fornisce i seguenti risultati:

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]

Consideriamo un nuovo esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System

Module string2
    Sub Main()
        ' la riga da analizzare
        Dim ligne As String = "un:deux::trois:"
        ' i separatori di campo
        Dim séparateurs() As Char = {":"c}
        ' divisione
        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 i risultati dell'esecuzione:

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

Il metodo Split della classe String consente di inserire in un array i campi di una stringa di caratteri. La definizione del metodo qui utilizzato è la seguente:

Overloads Public Function Split(ByVal ParamArray separator() As Char) As String()
separator
array di caratteri. Questi caratteri rappresentano i caratteri utilizzati per separare i campi della stringa. Pertanto, se la stringa è [champ1, champ2, champ3], si potrà utilizzare separator=new char() {","c}. Se il separatore è una sequenza di spazi, si utilizzerà separator=nothing.
résultat
array di stringhe in cui ogni elemento è un campo della stringa.

Il metodo Join è un metodo statico della classe String:

Overloads Public Shared Function Join(ByVal separator As String,ByVal value() As String) As String
value
array di stringhe
separator
una stringa che fungerà da separatore di campi
résultat
una stringa di caratteri formata dalla concatenazione degli elementi dell'array value, separati dalla stringa separator.

4.4. La classe Array

La classe Array implementa un array. Nel nostro esempio utilizzeremo le seguenti proprietà e metodi:

Public ReadOnly Property Length As Integer
proprietà - numero di elementi dell'array
Overloads Public Shared Function BinarySearch
(ByVal array As Array,ByVal index As Integer,
ByVal length As Integer,ByVal value As Object) As Integer
metodo di classe - restituisce la posizione di value nell'array ordinato array - effettua la ricerca a partire dalla posizione index e con length elementi
Overloads Public Shared Sub Copy(ByVal sourceArray 
As Array,ByVal destinationArray As Array,
ByVal length As Integer)
metodo di classe - copia gli elementi di length da sourceArray in destinationArray - destinationArray viene creato per l'occasione
Overloads Public Shared Sub Sort(ByVal array As Array)
metodo di classe - ordina l'array array - quest'ultimo deve contenere un tipo di dati con una funzione di ordinamento predefinita (stringhe, numeri).

Il seguente programma illustra l'utilizzo della classe Array:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System

Module test
    Sub Main()
        ' lettura degli elementi di un array digitati dalla tastiera
        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é
            ' domanda
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' lettura della risposta
            réponse = Console.ReadLine().Trim()
            ' fine dell'inserimento se la stringa è vuota
            If réponse.Equals("") Then
                Exit While
            End If
            ' verifica dell'inserimento
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se non ci sono errori
            If Not erreur Then
                ' nuova tabella per inserire il nuovo elemento
                éléments2 = New Double(i) {}
                ' copia del vecchio array nel nuovo array
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' il nuovo array diventa il vecchio array
                éléments1 = éléments2
                ' il nuovo array non è più necessario
                éléments2 = Nothing
                ' inserimento di un nuovo elemento
                éléments1(i) = élément
                ' un elemento in più nella tabella
                i += 1
            End If
        End While
        ' visualizzazione della tabella non ordinata
        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
        ' ordinamento della tabella
        System.Array.Sort(éléments1)
        ' Visualizzazione della tabella ordinata
        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
        ' Ricerca
        While Not terminé
            ' domanda
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' lettura e verifica della risposta
            réponse = Console.ReadLine().Trim()
            ' finito?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verifica
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se non ci sono errori
            If Not erreur Then
                ' si cerca l'elemento nell'array ordinato
                i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
                ' Visualizzazione della risposta
                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

I risultati visualizzati sullo schermo sono i seguenti:

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) :

La prima parte del programma crea un array a partire dai dati numerici digitati dalla tastiera. Le dimensioni dell'array non possono essere definite in anticipo, poiché non si conosce il numero di elementi che l'utente digiterà. Si lavora quindi con due array: éléments1 e éléments2.


                ' nuovo array per contenere il nuovo elemento
                éléments2 = New Double(i) {}
                ' copia del vecchio array nel nuovo array
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' La nuova tabella diventa la vecchia tabella
                éléments1 = éléments2
                ' la nuova tabella non è più necessaria
                éléments2 = Nothing
                ' inserimento di un nuovo elemento
                éléments1(i) = élément
                ' un elemento in più nella tabella
                i += 1

L’array éléments1 contiene i valori attualmente inseriti. Quando l’utente aggiunge un nuovo valore, viene creato un array éléments2 con un elemento in più rispetto a éléments1, si copia il contenuto di éléments1 in éléments2 (Array.Copy), si fa in modo che éléments1 «punti» a éléments2 e infine si aggiunge il nuovo elemento a éléments1. Si tratta di un processo complesso che può essere semplificato se, invece di utilizzare un array di dimensione fissa (Array), si utilizza un array di dimensione variabile (ArrayList).

L'array viene ordinato con il metodo Array.Sort. Questo metodo può essere chiamato con diversi parametri che specificano le regole di ordinamento. Senza parametri, per impostazione predefinita viene eseguito un ordinamento in ordine crescente. Infine, il metodo Array.BinarySearch consente di cercare un elemento in un array ordinato.

4.5. La classe ArrayList

La classe ArrayList consente di implementare array di dimensione variabile durante l’esecuzione del programma, cosa che la precedente classe Array non permette. Ecco alcune delle proprietà e dei metodi più comuni:

Public Sub New()
crea un elenco vuoto
Public Overridable ReadOnly Property Count 
As Integer  Implements ICollection.Count
numero di elementi della collezione
Public Overridable Function Add(ByVal value 
As Object) As Integer Implements IList.Add
aggiunge l'oggetto value alla fine della collezione
Public Overridable Sub Clear() 
Implements IList.Clear
cancella l'elenco
Overloads Public Overridable Function 
IndexOf(ByVal value As Object) As Integer 
Implements IList.IndexOf
indice dell'oggetto value nell'elenco oppure -1 se non esiste
Overloads Public Overridable Function 
IndexOf(ByVal value As Object, ByVal startIndex 
As Integer) As Integer
idem, ma con ricerca a partire dall'elemento n. startIndex
Overloads Public Overridable Function 
LastIndexOf(ByVal value As Object) As Integer
idem, ma restituisce l'indice dell'ultima occorrenza di value nell'elenco
Overloads Public Overridable Function 
LastIndexOf(ByVal value As Object, ByVal startIndex As Integer) As Integer
idem, ma effettuando la ricerca a partire dall'elemento n. startIndex
Public Overridable Sub Remove( ByVal obj As Object)
Implements IList.Remove
elimina l'oggetto obj se presente nell'elenco
Public Overridable Sub RemoveAt(ByVal index As Integer) 
Implements IList.RemoveAt
rimuove l'elemento index dall'elenco
Overloads Public Overridable Function 
BinarySearch(ByVal value As Object) As Integer
restituisce la posizione dell'oggetto "value" nell'elenco oppure -1 se non è presente. L'elenco deve essere ordinato
Overloads Public Overridable Sub Sort()
ordina la lista. Questa deve contenere oggetti con una relazione di ordine predefinita (stringhe, numeri)
Overloads Public Overridable Sub 
Sort(ByVal comparer As IComparer)
ordina la lista in base alla relazione di ordine stabilita dalla funzione di confronto

Riprendiamo l’esempio trattato con oggetti di tipo Array e elaboriamolo con oggetti di tipo ArrayList:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections

Module test
    Sub Main()
        ' lettura degli elementi di una tabella digitati dalla tastiera
        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é
            ' domanda
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' lettura della risposta
            réponse = Console.ReadLine().Trim()
            ' fine dell'inserimento se la stringa è vuota
            If réponse.Equals("") Then
                Exit While
            End If
            ' verifica dell'inserimento
            Try
                élément = Double.Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se non ci sono errori
            If Not erreur Then
                ' un elemento in più nell'array
                éléments.Add(élément)
            End If
        End While
        ' visualizzazione dell'array non ordinato
        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()
        ' visualizzazione tabella ordinata
        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
        ' Ricerca
        While Not terminé
            ' domanda
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' Lettura e verifica della risposta
            réponse = Console.ReadLine().Trim()
            ' finito?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verifica
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' se non ci sono errori
            If Not erreur Then
                ' si cerca l'elemento nell'array ordinato
                i = éléments.BinarySearch(élément)
                ' Visualizzazione della risposta
                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

I risultati dell’esecuzione sono i seguenti:

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. La classe Hashtable

La classe Hashtable consente di implementare un dizionario. È possibile considerare un dizionario come una tabella a due colonne:

Le chiavi sono uniche, c.a.d, ovvero non possono esserci due chiavi identiche. I principali metodi e proprietà della classe Hashtable sono i seguenti:

Public Sub New()
crea un dizionario vuoto
Public Overridable Sub Add(ByVal key As
Object,ByVal value As Object) 
Implements IDictionary.Add
aggiunge una riga (chiave, valore) nel dizionario, dove chiave e valore sono riferimenti a oggetti.
Public Overridable Sub Remove
(ByVal key As Object) Implements IDictionary.Remove
elimina dal dizionario la riga con chiave=key
Public Overridable Sub Clear() 
Implements IDictionary.Clear
svuota il dizionario
Public Overridable Function ContainsKey
(ByVal key As Object) As Boolean
restituisce "vero" (true) se la chiave key è presente nel dizionario.
Public Overridable Function 
ContainsValue(ByVal value As Object) As Boolean
restituisce vero (true) se il valore value è presente nel dizionario.
Public Overridable ReadOnly Property 
Count As Integer  Implements ICollection.Count
proprietà: numero di elementi del dizionario (chiave, valore)
Public Overridable ReadOnly Property 
Keys As ICollection Implements IDictionary.Keys
proprietà: insieme delle chiavi del dizionario
Public Overridable ReadOnly Property 
Values As ICollection Implements IDictionary.Values
proprietà: insieme dei valori del dizionario
Public Overridable Default Property 
Item(ByVal key As Object) As Object  Implements IDictionary.Item
proprietà indicizzata: consente di conoscere o impostare il valore associato a una chiave

Consideriamo il seguente programma di esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
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}
        ' Compilazione del dizionario
        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
        ' numero di elementi nel dizionario
        Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
        ' elenco delle chiavi
        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
        ' elenco dei valori
        Console.Out.WriteLine("[Liste des valeurs]")
        Dim valeurs As IEnumerator = dico.Values.GetEnumerator()
        While valeurs.MoveNext()
            Console.Out.WriteLine(valeurs.Current)
        End While
        ' elenco delle chiavi e dei valori
        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
        ' si elimina la chiave "paul"
        Console.Out.WriteLine("[Suppression d'une clé]")
        dico.Remove("paul")
        ' elenco delle chiavi e dei valori
        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

        ' ricerca nel dizionario
        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
            ' ricerca successiva
            Console.Out.Write("Nom recherché (rien pour arrêter) : ")
            nomCherché = Console.ReadLine().Trim()
        End While
    End Sub
End Module

I risultati dell'esecuzione sono i seguenti:

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) :

Il programma utilizza inoltre un oggetto IEnumerator per scorrere le collezioni di chiavi e valori del dizionario di tipo ICollection (cfr. sopra le proprietà Keys e Values). Una collezione è un insieme di oggetti che è possibile scorrere. L’interfaccia ICollection è definita come segue:

Image

La proprietà Count ci permette di conoscere il numero di elementi della collezione. L'interfaccia ICollection deriva dall'interfaccia IEnumerable:

Image

Questa interfaccia ha un solo metodo, GetEnumerator, che ci permette di ottenere un oggetto di tipo IEnumerator:

Image

Il metodo GetEnumerator() di una collezione ICollection ci permette di iterare sulla collezione con i seguenti metodi:

MoveNext
posiziona sul successivo elemento della collezione. Restituisce vero (true) se tale elemento esiste, falso (false) in caso contrario. Il primo MoveNext posiziona sul primo elemento. L'elemento "corrente" della collezione è quindi disponibile nella proprietà Current dell'enumeratore
Current
proprietà: elemento corrente della collezione
Reset
riposiziona l'iteratore all'inizio della collezione, c.a.d, prima del primo elemento.

La struttura di iterazione sugli elementi di una collezione (ICollection) in C è quindi la seguente:

' definire la collezione
dim C as ICollection C=...
' ottenere un enumeratore di questa collezione
dim itérateur as IEnumerator=C.GetEnumerator();
' scorrere la collezione con questo enumeratore
while(itérateur.MoveNext())
    ' si ha un elemento corrente
     ' utilizzare itérateur.Current
end while

4.7. La classe StreamReader

La classe StreamReader consente di leggere il contenuto di un file. Ecco alcune delle sue proprietà e dei suoi metodi:

Public Sub New(ByVal path As String)
apre un flusso dal file path. Se il file non esiste, viene generata un'eccezione
Overrides Public Sub Close()
chiude il flusso
Overrides Public Function ReadLine() As String
legge una riga dal flusso aperto
Overrides Public Function ReadToEnd() As String
legge il resto del flusso a partire dalla posizione corrente

Ecco un esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections
Imports System.IO

Module test
    Sub Main()
        Dim ligne As String = Nothing
        Dim fluxInfos As StreamReader = Nothing
        ' lettura del contenuto del file
        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 i relativi risultati di esecuzione:

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. La classe StreamWriter

La classe StreamWriter consente di scrivere su un file. Ecco alcune delle sue proprietà e dei suoi metodi:

Public Sub New(ByVal path As String)
apre un flusso di scrittura dal file path. Se il file non può essere creato, viene generata un'eccezione
Public Overridable Property AutoFlush 
As Boolean
se è uguale a vero, la scrittura nel flusso non passa attraverso un buffer; altrimenti la scrittura nel flusso non è immediata: prima si scrive in un buffer e poi nel flusso quando il buffer è pieno. Per impostazione predefinita viene utilizzata la modalità con buffer. È adatta per i flussi di file ma generalmente non per i flussi di rete.
Public Overridable Property NewLine 
As String
per impostare o conoscere il carattere di fine riga da utilizzare con il metodo WriteLine
Overrides Public Sub Close()
chiude il flusso
Overloads Public Overridable Sub 
WriteLine(ByVal value As String)
scrive una riga nel flusso di scrittura
Overrides Public Sub Flush()
scrive il buffer nel flusso

Consideriamo il seguente esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
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
            ' creazione del file di testo
            fluxInfos = New StreamWriter("infos.txt")
            ' lettura della riga digitata dalla tastiera
            Console.Out.Write("ligne (rien pour arrêter) : ")
            ligne = Console.In.ReadLine().Trim()
            ' ciclo finché la riga inserita non è vuota
            While ligne <> ""
                ' scrittura della riga nel file di testo
                fluxInfos.WriteLine(ligne)
                ' lettura della nuova riga digitata dalla tastiera
                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
            ' chiusura del file
            Try
                fluxInfos.Close()
            Catch
            End Try
        End Try
    End Sub
End Module

e i risultati dell'esecuzione:

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. La classe Regex

La classe Regex consente l'utilizzo di espressioni regolari. Queste permettono di verificare il formato di una stringa di caratteri. In questo modo è possibile verificare che una stringa che rappresenta una data sia effettivamente nel formato gg/mm/aa. A tal fine si utilizza un modello e si confronta la stringa con tale modello. In questo esempio, quindi, j, m e a devono essere cifre. Il modello di un formato di data valido è quindi "\d\d/\d\d/\d\d", dove il simbolo \d indica una cifra. I simboli utilizzabili in un modello sono i seguenti (documentazione Microsoft):

 
Descrizione
\ 
Contrassegna il carattere successivo come carattere speciale o letterale. Ad esempio, "n" corrisponde al carattere "n". "\n" corrisponde a un carattere di nuova riga. La sequenza "\\" corrisponde a "\", mentre "\(" corrisponde a "(".
^ 
Corrisponde all’inizio dell’immissione.
$ 
Corrisponde alla fine dell'inserimento.
* 
Corrisponde al carattere precedente zero o più volte. Pertanto, "zo*" corrisponde a "z" o a "zoo".
+ 
Corrisponde al carattere precedente una o più volte. Pertanto, "zo+" corrisponde a "zoo", ma non a "z".
? 
Corrisponde al carattere precedente zero o una volta. Ad esempio, "a?ve?" corrisponde a "ve" in "lever".
.
Corrisponde a qualsiasi carattere singolo, eccetto il carattere di nuova riga.

(modèle) 
Cerca modèle e memorizza la corrispondenza. La sottostringa corrispondente può essere estratta dalla raccolta Matches ottenuta, utilizzando l'elemento [0]...[n]. Per trovare corrispondenze con caratteri tra parentesi ( ), utilizzare "\(" o "\)".

x|y
Corrisponde sia a x sia a y. Ad esempio, "z|foot" corrisponde a "z" o a "foot". "(z|f)oo" corrisponde a "zoo" o a "foo".

{n}
n è un numero intero non negativo. Corrisponde esattamente a n moltiplicato per il carattere. Ad esempio, "o{2}" non corrisponde alla "o" in "Bob," ma alle prime due "o" in "fooooot".

{n,} 
n è un numero intero non negativo. Corrisponde ad almeno n volte il carattere. Ad esempio, "o{2,}" non corrisponde alla "o" in "Bob", ma a tutte le "o" in "fooooot". "o{1,}" equivale a "o+" e "o{0,}" equivale a "o*".

{n,m} 
m e n sono numeri interi non negativi. Corrisponde ad almeno n e al massimo m volte il carattere. Ad esempio, "o{1,3}" corrisponde alle prime tre "o" in "foooooot" e "o{0,1}" equivale a "o?".

[xyz] 
Set di caratteri. Corrisponde a uno dei caratteri indicati. Ad esempio, "[abc]" corrisponde alla "a" in "plat".

[^xyz] 
Set di caratteri negativo. Corrisponde a qualsiasi carattere non indicato. Ad esempio, "[^abc]" corrisponde alla "p" in "plat".

[a-z] 
Intervallo di caratteri. Corrisponde a qualsiasi carattere compreso nella serie specificata. Ad esempio, "[a-z]" corrisponde a qualsiasi carattere alfabetico minuscolo compreso tra "a" e "z".

[^m-z] 
Intervallo di caratteri negativo. Corrisponde a qualsiasi carattere non presente nella serie specificata. Ad esempio, "[^m-z]" corrisponde a qualsiasi carattere non compreso tra "m" e "z".
\b 
Corrisponde a un limite che rappresenta una parola, in altre parole, alla posizione tra una parola e uno spazio. Ad esempio, "er\b" corrisponde a "er" in "lever", ma non a "er" in "verbe".
\B 
Corrisponde a un limite che non rappresenta una parola. «en*t\B» corrisponde a «ent» in «bien entendu».
\d 
Corrisponde a un carattere che rappresenta una cifra. Equivale a [0-9].
\D 
Corrisponde a un carattere che non rappresenta una cifra. Equivale a [^0-9].
\f 
Corrisponde a un carattere di fine pagina.
\n 
Corrisponde a un carattere di nuova riga.
\r 
Corrisponde a un carattere di ritorno a capo.
\s 
Corrisponde a qualsiasi spazio bianco, inclusi spazio, tabulazione, salto di pagina, ecc. Equivale a "[ \f\n\r\t\v]".
\S 
Corrisponde a qualsiasi carattere di spazio non bianco. Equivale a "[^ \f\n\r\t\v]".
\t 
Corrisponde a un carattere di tabulazione.
\v 
Corrisponde a un carattere di tabulazione verticale.
\w 
Corrisponde a qualsiasi carattere che rappresenti una parola e che includa un trattino basso. Equivale a "[A-Za-z0-9_]".
\W 
Corrisponde a qualsiasi carattere che non rappresenti una parola. Equivale a "[^A-Za-z0-9_]".

\num 
Corrisponde a num, dove num è un numero intero positivo. Si riferisce alle corrispondenze memorizzate. Ad esempio, «(.)\1» corrisponde a due caratteri identici consecutivi.

\n
Corrisponde a n, dove n è un valore di escape ottale. I valori di escape ottali devono comprendere 1, 2 o 3 cifre. Ad esempio, sia "\11" che "\011" corrispondono a un carattere di tabulazione. "\0011" equivale a "\001" e "1". I valori di escape ottali non devono superare 256. In caso contrario, nell'espressione verrebbero prese in considerazione solo le prime due cifre. Consente di utilizzare i codici ASCII nelle espressioni regolari.

\xn
Corrisponde a n, dove n è un valore di escape esadecimale. I valori di escape esadecimali devono obbligatoriamente comprendere due cifre. Ad esempio, "\x41" corrisponde a "A". "\x041" equivale a "\x04" e "1". Consente di utilizzare i codici ASCII nelle espressioni regolari.

Un elemento in un modello può essere presente una o più volte. Consideriamo alcuni esempi relativi al simbolo \d, che rappresenta una cifra:

modello
significato
\d
una cifra
\d?
0 o 1 cifra
\d*
0 o più cifre
\d+
1 o più cifre
\d{2}
2 cifre
\d{3,}
almeno 3 cifre
\d{5,7}
da 5 a 7 cifre

Immaginiamo ora il modello in grado di descrivere il formato previsto per una stringa di caratteri:

stringa ricercata
modello
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
\bjuste\b
  

È possibile specificare dove cercare il modello nella stringa:

modello
significato
^modèle
il modello inizia la stringa
modèle$
il modello termina la stringa
^modèle$
il modello inizia e termina la stringa
modèle
il modello viene cercato in tutta la stringa a partire dall'inizio della stessa.
stringa ricercata
modello
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

I sottoinsiemi di un modello possono essere "recuperati". In questo modo, non solo è possibile verificare che una stringa corrisponda a un modello specifico, ma è anche possibile recuperare all'interno di tale stringa gli elementi corrispondenti ai sottoinsiemi del modello che sono stati racchiusi tra parentesi. Pertanto, se si analizza una stringa contenente una data gg/mm/aa e si desidera inoltre estrarre gli elementi gg, mm, aa di tale data, si utilizzerà il modello (\d\d)/(\d\d)/(\d\d).

4.9.1. Verificare che una stringa corrisponda a un modello dato

Un oggetto di tipo Regex si costruisce nel modo seguente:

Public Sub New(ByVal pattern As String)

Il costruttore crea un oggetto «espressione regolare» a partire da un modello passato come parametro (pattern). Una volta costruita l’espressione regolare modello, è possibile confrontarla con stringhe di caratteri utilizzando il metodo IsMatch:

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

IsMatch restituisce vero se la stringa di input corrisponde al modello dell'espressione regolare. Ecco un esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex1

    Sub Main()
        ' un'espressione regolare modello
        Dim modèle1 As String = "^\s*\d+\s*$"
        Dim regex1 As New Regex(modèle1)
        ' confronta un elemento con il modello
        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

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

e i risultati dell’esecuzione:

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. Trovare tutti gli elementi di una stringa che corrispondono a un modello

Il metodo Matches

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

restituisce una collezione di elementi della stringa input che corrispondono al modello, come illustrato nell'esempio seguente:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' più occorrenze del modello nell'esempio
        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

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

La classe MatchCollection ha una proprietà Count che rappresenta il numero di elementi della collezione. Se résultats è un oggetto MatchCollection, résultats(i) è l'elemento i di tale collezione ed è di tipo Match. Nel nostro esempio, résultats è l'insieme degli elementi della stringa exemplaire3 corrispondenti al modello modèle2 e résultats(i) è uno di questi elementi. La classe Match presenta due proprietà che ci interessano in questo contesto:

  • Value: il valore dell’oggetto Match, ovvero l’elemento corrispondente al modello
  • Index: la posizione in cui l’elemento è stato trovato nella stringa analizzata

I risultati dell’esecuzione del programma precedente:

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. Estrazione di parti di un modello

È possibile "estrarre" sottoinsiemi di un modello. In questo modo, non solo è possibile verificare che una stringa corrisponda a un modello specifico, ma è anche possibile estrarre da tale stringa gli elementi corrispondenti ai sottoinsiemi del modello racchiusi tra parentesi. Pertanto, se si analizza una stringa contenente una data gg/mm/aa e si desidera inoltre estrarre gli elementi gg, mm, aa di tale data, si utilizzerà il modello (\d\d)/(\d\d)/(\d\d). Esaminiamo il seguente esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' acquisizione di elementi nel modello
        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 del modello
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' la copia corrisponde al modello
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' vengono visualizzati i gruppi
            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
            ' l'esemplare non corrisponde al modello
            affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
        End If
    End Sub

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

L’esecuzione di questo programma produce i seguenti risultati:

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

La novità si trova nella seguente porzione di codice:


        ' verifica modello
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' l'esemplare corrisponde al modello
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' vengono visualizzati i gruppi
            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

La stringa exemplaire4 viene confrontata con il modello regex3 tramite il metodo Match. Quest'ultimo restituisce un oggetto Match già presentato. Qui utilizziamo due nuove proprietà di questa classe:

  • Success: indica se è stata trovata una corrispondenza
  • Groups: raccolta in cui
    • Groups[0] corrisponde alla parte della stringa corrispondente al modello
    • Groups[i] (i>=1) corrisponde al gruppo di parentesi n. i

Se il risultato è di tipo Match, résultats.Groups è di tipo GroupCollection e résultats.Groups[i] è di tipo Group. La classe Group presenta due proprietà che utilizziamo in questo contesto:

  • Value: il valore dell’oggetto Group a cui corrisponde l’elemento contenente il contenuto di una parentesi
  • Index: la posizione in cui l’elemento è stato trovato nella stringa analizzata

4.9.4. Un programma di esercitazione

Trovare l’espressione regolare che ci consenta di verificare che una stringa corrisponda effettivamente a un determinato modello è talvolta una vera sfida. Il programma seguente permette di esercitarsi. Richiede un modello e una stringa e indica quindi se la stringa corrisponde o meno al modello.


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic

Module regex4
    Sub Main()
        ' un'espressione regolare modello
        Dim modèle, chaine As String
        Dim regex As Regex = Nothing
        Dim résultats As MatchCollection
        ' si chiede all'utente quali modelli e istanze confrontare con questo
        Dim terminé1 As Boolean = False
        Do While Not terminé1
            Dim erreur As Boolean = True
            Do While Not terminé1 And erreur
                ' viene richiesto il modello
                Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
                modèle = Console.In.ReadLine()
                ' finito?
                If modèle.Trim().ToLower() = "fin" Then
                    terminé1 = True
                Else
                    ' si crea l'espressione regolare
                    Try
                        regex = New Regex(modèle)
                        erreur = False
                    Catch ex As Exception
                        Console.Error.WriteLine(("Erreur : " + ex.Message))
                    End Try
                End If
            Loop
            ' Finito?
            If terminé1 Then Exit Sub
            ' si chiede all’utente quali istanze confrontare con il modello
            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()
                ' finito?
                If chaine.Trim().ToLower() = "fin" Then
                    terminé2 = True
                Else
                    ' si esegue il confronto
                    résultats = regex.Matches(chaine)
                    ' Operazione riuscita?
                    If résultats.Count = 0 Then
                        Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
                    Else
                        ' vengono visualizzati gli elementi corrispondenti al modello
                        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))
                            ' sottoelementi
                            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

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

Ecco un esempio di esecuzione:

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. Il metodo Split

Abbiamo già incontrato questo metodo nella classe String:

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

La stringa viene considerata come una sequenza di campi separati dai caratteri presenti nella tabella [separator]. Il risultato è la tabella di questi campi.

Il separatore dei campi della stringa è in questo caso uno dei caratteri della tabella separator. Il metodo Split della classe Regex ci permette di specificare il separatore in base a un modello:

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

La stringa [input] viene scomposta in campi, separati da un separatore corrispondente al modello dell’oggetto Regex corrente. Supponiamo, ad esempio, di avere in un file di testo delle righe della forma campo1, campo2, ..., campo n. I campi sono separati da una virgola, ma questa può essere preceduta o seguita da spazi. Il metodo Split della classe string non è quindi adatto. La soluzione è fornita dal metodo RegEx. Se «riga» è la riga letta, i campi potranno essere ottenuti tramite

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

come mostra il seguente esempio:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Text.RegularExpressions

Module regex5
    Sub Main()
        ' una riga
        Dim ligne As String = "abc  , def  , ghi"
        ' un modello
        Dim modèle As New Regex("\s*,\s*")
        ' scomposizione della riga in campi
        Dim champs As String() = modèle.Split(ligne)
        ' visualizzazione
        Dim i As Integer
        For i = 0 To champs.Length - 1
            Console.Out.WriteLine(("champs[" & i & "]=[" & champs(i) & "]"))
        Next i
    End Sub
End Module

Risultati dell’esecuzione:

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. Le classi BinaryReader e BinaryWriter

Le classi BinaryReader e BinaryWriter servono a leggere e scrivere file binari. Consideriamo la seguente applicazione. Vogliamo scrivere un programma che verrebbe chiamato come segue:

// sintassi pg testo bin
// si legge un file di testo (testo) e se ne memorizza il contenuto in un
// file binario
// il file di testo contiene righe della forma nome : età
// che verranno memorizzate in una struttura string, int

Il file di testo contiene quanto segue:

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

Il programma è il seguente:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

' BinaryWriter()

Module bw1
    ' sintassi pg testo bin
    ' si legge un file di testo (testo) e se ne memorizza il contenuto in un
    ' file binario
    ' il file di testo contiene righe della forma nome : età
    ' che verranno memorizzate in una struttura string, int

    Sub Main(ByVal arguments() As String)
        ' sono necessari 2 argomenti
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg texte binaire")
            Environment.Exit(1)
        End If
        ' apertura del file di testo in lettura
        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
        ' apertura del file binario in scrittura
        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
        ' lettura del file di testo - scrittura del file binario
        ' riga del file di testo
        Dim ligne As String
        ' il separatore dei campi della riga
        Dim séparateur As New Regex("\s*:\s*")
        ' il formato dell'età
        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
            ' riga vuota?
            If ligne.Trim() = "" Then
                traitementFini = True
            End If
            ' un'altra riga
            If Not traitementFini Then
                numLigne += 1
                ' una riga nome: età
                champs = séparateur.Split(ligne)
                ' ci servono 2 campi
                If champs.Length <> 2 Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
                    ' riga successiva
                    traitementFini = True
                End If
            End If
            If Not traitementFini Then
                ' il secondo campo deve essere un numero intero >=0
                If Not modAge.IsMatch(champs(1)) Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
                    ' riga successiva
                    traitementFini = True
                End If
                ' si scrivono i dati nel file binario
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))
            End If
            'riga successiva
            ligne = input.ReadLine()
        End While
        ' chiusura dei file
        input.Close()
        output.Close()
    End Sub
End Module

Soffermiamoci sulle operazioni relative alla classe BinaryWriter:

  • l'oggetto BinaryWriter viene aperto dall'operazione

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

L'argomento del costruttore deve essere uno stream. In questo caso si tratta di uno stream creato a partire da un file (FileStream) di cui si specificano:

  • (continua)
    • il nome
    • l'operazione da eseguire, in questo caso FileMode.Create per creare il file
    • il tipo di accesso, in questo caso FileAccess.Write per un accesso in scrittura al file
  • l’operazione di scrittura

                 ' si scrivono i dati nel file binario
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))

La classe BinaryWriter dispone di diversi metodi Write sovrascritti per scrivere i diversi tipi di dati semplici

  • l'operazione di chiusura del flusso
        output.Close()

I risultati dell'esecuzione precedente ci verranno forniti dal programma che segue. Anche questo accetta due argomenti:

     ' sintassi pg bin testo
     ' si legge un file binario bin e se ne salva il contenuto in un file di testo (testo)
     ' il file binario ha una struttura string, int
     ' il file di testo contiene righe della forma nome : età

Si esegue quindi l'operazione inversa. Si legge un file binario per creare un file di testo. Se il file di testo prodotto è identico al file originale, sapremo che la conversione testo --> binario --> testo è andata a buon fine. Il codice è il seguente:


' opzioni
Option Strict On
Option Explicit On 

' spazi dei nomi
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

Module br1
    ' sintassi pg bin testo
    ' si legge un file binario bin e se ne salva il contenuto in un file di testo (testo)
    ' il file binario ha una struttura string, int
    ' il file di testo contiene righe della forma nome : età

    Sub Main(ByVal arguments() As String)
        ' sono necessari 2 argomenti
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg binaire texte")
            Environment.Exit(1)
        End If
        ' apertura del file binario in lettura
        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
        ' apertura del file di testo in scrittura
        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
        ' lettura del file binario - scrittura del file di testo
        Dim nom As String        ' nom d'une personne
        Dim age As Integer        ' son âge
        ' ciclo di elaborazione del file binario
        While True
            ' lettura del nome
            Try
                nom = dataIn.ReadString()
            Catch
                ' fine del file
                Exit Sub
            End Try
            ' lettura dell'età
            Try
                age = dataIn.ReadInt32()
            Catch
                Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
                Exit Sub
            End Try
            ' scrittura nel file di testo
            dataOut.WriteLine(nom & ":" & age)
            System.Console.WriteLine(nom & ":" & age)
        End While
        ' chiusura di tutto
        dataIn.Close()
        dataOut.Close()
    End Sub
End Module

Soffermiamoci sulle operazioni relative alla classe BinaryReader:

  • l'oggetto BinaryReader viene aperto dall'operazione

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

L'argomento del costruttore deve essere uno stream. In questo caso si tratta di uno stream creato a partire da un file (FileStream) di cui si specificano:

  • (continua)
    • il nome
    • l'operazione da eseguire, in questo caso FileMode.Open per aprire un file esistente
    • il tipo di accesso, in questo caso FileAccess.Read per un accesso in lettura al file
  • l’operazione di lettura
                nom = dataIn.ReadString()
                age = dataIn.ReadInt32()

La classe BinaryReader dispone di diversi metodi ReadXX per leggere i diversi tipi di dati semplici

  • l'operazione di chiusura del flusso
        dataIn.Close()

Se si eseguono in sequenza i due programmi che trasformano personnes.txt in personnes.bin e poi personnes.bin in personnes.txt2, si ottiene:

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