Skip to content

4. Clases .NET de uso común

A continuación presentamos algunas clases de la plataforma .NET que resultan interesantes, incluso para un principiante. En primer lugar, mostramos cómo obtener información sobre los cientos de clases disponibles.

4.1. Buscar ayuda con SDK.NET

4.1.1. wincv

Si solo se ha instalado SDK y no Visual Studio.NET, se podrá utilizar el programa wincv.exe, que normalmente se encuentra en el árbol de directorios del SDK, por ejemplo, C:\Archivos de programa\Microsoft Visual Studio .NET 2003\SDK\v1.1. Al ejecutar esta utilidad, aparece la siguiente interfaz:

En (1) se escribe el nombre de la clase deseada. Esto muestra en (2) varios temas posibles. Se elige el que convenga y se obtiene el resultado en (3), en este caso la clase HashTable. Este método es adecuado si se conoce el nombre de la clase que se busca. Si se desea explorar la lista de posibilidades que ofrece la plataforma .NET o se puede utilizar el archivo HTML StartHere.htm, que también se encuentra directamente en la carpeta de instalación de SSK.Net, por ejemplo, C:\Archivos de programa\Microsoft Visual Studio .NET 2003\SDK\v1.

Image

El enlace .NET Framework SDK Documentación es el que hay que seguir para obtener una visión general de las clases .NET:

Image

Allí, seguiremos el enlace [Bibliothèque de classes]. En él se encuentra la lista de todas las clases de .NET:

Image

Sigamos, por ejemplo, el enlace System.Collections. Este espacio de nombres agrupa diversas clases que implementan colecciones, entre ellas la clase HashTable:

Image

Sigamos el enlace HashTable que aparece a continuación:

Image

Obtenemos la siguiente página:

Image

Fíjate en la posición de la mano. Apunta a un enlace que permite especificar el lenguaje deseado, en este caso Visual Basic.

Allí encontramos el prototipo de la clase, así como ejemplos de uso. Sigamos el enlace [Hashtable, membres] que aparece a continuación:

Image

Se obtiene la descripción completa de la clase:

Image

Este método es el mejor para descubrir SDK y sus clases. La herramienta WinCV resulta útil cuando ya se conoce un poco la clase y se han olvidado algunos de sus miembros. WinCV permite entonces encontrar rápidamente la clase y sus miembros.

4.2. Buscar ayuda sobre las clases con VS.NET

A continuación ofrecemos algunas indicaciones para encontrar ayuda con Visual Studio.NET

4.2.1. Opción Ayuda

Seleccionemos la opción [?] del menú.

Image

Aparece la siguiente ventana:

Image

En la lista desplegable, podemos elegir un filtro de ayuda. Aquí, seleccionaremos el filtro [Visual Basic].

Image

Hay dos ayudas útiles:

  • la ayuda sobre el propio lenguaje VB.NET (sintaxis)
  • la ayuda sobre los classes.NET que puede utilizar el lenguaje VB.NET

Se puede acceder a la ayuda del lenguaje VB.NET a través de [Visual Studio.NET/Visual Basic et Visual C#/Reference/Visual Basic]:

Image

Se obtiene la siguiente página de ayuda:

Image

A partir de ahí, las diferentes subsecciones nos permiten obtener ayuda sobre diversos temas de VB.NET. Prestaremos atención a los tutoriales de VB.NET:

Image

Para acceder a las diferentes clases de la plataforma .NET, seleccionaremos la ayuda [Visual Studio.NET/.NET Framework].

Image

Nos centraremos especialmente en la sección [Référence/Bibliothèque de classes]:

Image

Supongamos que nos interesa la clase [ArrayList]. Se encuentra en el espacio de nombres [System.Collections]. Es importante saberlo; de lo contrario, se preferirá el método de búsqueda que se expone a continuación. Se obtiene la siguiente ayuda:

Image

El enlace [ArrayList, classe] ofrece una visión general de la clase:

Image

Este tipo de página existe para todas las clases. Ofrece un resumen de la clase con ejemplos. Para obtener una descripción de los miembros de la clase, se seguirá el enlace [ArrayList, membres]:

Image

4.2.2. Ayuda/Índice

Image

La opción [Aide/index] permite buscar ayuda más específica que la anterior. Basta con escribir la palabra clave que se busca:

Image

La ventaja de este método con respecto al anterior es que no es necesario saber dónde se encuentra lo que se busca en el sistema de ayuda. Probablemente sea el método preferible cuando se realiza una búsqueda específica, mientras que el otro método es más adecuado para descubrir todo lo que ofrece la ayuda.

4.3. La clase String

La clase String presenta numerosas propiedades y métodos. He aquí algunos de ellos:

Public ReadOnly Property Length As Integer
número de caracteres de la cadena
Public Default ReadOnly Property
Chars(ByVal index As Integer) As Char
propiedad indexada por defecto. [String].Chars(i) es el carácter n.º i de la cadena
Public Function EndsWith(ByVal value As String)
As Boolean
devuelve verdadero si la cadena termina en value
Public Function StartsWith(ByVal value As String)
As Boolean
devuelve verdadero si la cadena comienza por el valor
Overloads Public Function Equals(ByVal value
As String) As Boolean
devuelve verdadero si la cadena es igual a value
Overloads Public Function IndexOf(ByVal value
As String) As Integer
devuelve la primera posición en la cadena del valor value; la búsqueda comienza a partir del carácter n.º 0
Overloads Public Function IndexOf(ByVal value
As String,ByVal startIndex As Integer) As Integer
devuelve la primera posición en la cadena del valor de la cadena; la búsqueda comienza a partir del carácter n.º startIndex
Overloads Public Shared Function
Join(ByVal separator As String,ByVal value()
As String) As String
método de clase: devuelve una cadena de caracteres, resultado de la concatenación de los valores de la matriz value con el separador separator
Overloads Public Function Replace(ByVal oldChar
As Char,ByVal newChar As Char) As String
devuelve una cadena que es una copia de la cadena actual en la que el carácter oldChar ha sido sustituido por el carácter newChar
Overloads Public Function Split(ByVal ParamArray
separator() As Char) As String()
la cadena se considera una secuencia de campos separados por los caracteres presentes en la matriz separator. El resultado es la matriz de dichos campos
Overloads Public Function Substring(
ByVal startIndex As Integer,ByVal length As Integer)
As String
subcadena de la cadena actual que comienza en la posición startIndex y tiene length caracteres
Overloads Public Function ToLower()
As String
convierte la cadena actual a minúsculas
Overloads Public Function ToUpper()
As String
convierte la cadena actual a mayúsculas
Overloads Public Function Trim()
As String
elimina los espacios iniciales y finales de la cadena actual

Una cadena C puede considerarse como una matriz de caracteres. Así,

  • C.Chars(i) es el carácter i de C
  • C.Length es el número de caracteres de C

Consideremos el siguiente ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
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

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

La ejecución da los siguientes 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]

Veamos un nuevo ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System

Module string2
    Sub Main()
        ' la línea a analizar
        Dim ligne As String = "un:deux::trois:"
        ' los separadores de campos
        Dim séparateurs() As Char = {":"c}
        ' dividir
        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
        ' unir
        Console.Out.WriteLine(("join=[" + System.String.Join(":", champs) + "]"))
    End Sub
End Module

y los resultados de la ejecución:

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

El método Split de la clase String permite dividir los campos de una cadena de caracteres en una matriz. La definición del método que se utiliza aquí es la siguiente:

Overloads Public Function Split(ByVal ParamArray separator() As Char) As String()
separator
matriz de caracteres. Estos caracteres representan los caracteres utilizados para separar los campos de la cadena de caracteres. Así, si la cadena es [champ1, champ2, champ3], se podrá utilizar separator=new char() {","c}. Si el separador es una secuencia de espacios, se utilizará separator=nothing.
résultat
matriz de cadenas de caracteres en la que cada elemento es un campo de la cadena.

El método Join es un método estático de la clase String:

Overloads Public Shared Function Join(ByVal separator As String,ByVal value() As String) As String
value
matriz de cadenas de caracteres
separator
una cadena de caracteres que servirá como separador de campos
résultat
una cadena de caracteres formada por la concatenación de los elementos de la tabla value separados por la cadena separator.

4.4. La clase Array

La clase Array implementa una matriz. En nuestro ejemplo utilizaremos las siguientes propiedades y métodos:

Public ReadOnly Property Length As Integer
propiedad: número de elementos de la 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 clase: devuelve la posición de value en la tabla ordenada array; busca a partir de la posición index y con length elementos
Overloads Public Shared Sub Copy(ByVal sourceArray
As Array,ByVal destinationArray As Array,
ByVal length As Integer)
método de clase: copia los elementos de length de sourceArray a destinationArray; para ello, se crea destinationArray
Overloads Public Shared Sub Sort(ByVal array As Array)
método de clase: ordena la tabla array; esta debe contener un tipo de datos con una función de orden predeterminada (cadenas, números).

El siguiente programa ilustra el uso de la clase Array:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System

Module test
    Sub Main()
        ' lectura de los elementos de una matriz introducidos mediante el 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é
            ' pregunta
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' lectura de la respuesta
            réponse = Console.ReadLine().Trim()
            ' fin de la entrada si la cadena está vacía
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificación de la entrada
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' si no hay error
            If Not erreur Then
                ' nueva tabla para alojar el nuevo elemento
                éléments2 = New Double(i) {}
                ' copia de la tabla antigua a la nueva
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' la nueva tabla se convierte en la antigua
                éléments1 = éléments2
                ' ya no se necesita la nueva tabla
                éléments2 = Nothing
                ' Inserción de un nuevo elemento
                éléments1(i) = élément
                ' un elemento más en la tabla
                i += 1
            End If
        End While
        ' visualización de la tabla sin ordenar
        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
        ' ordenación de la tabla
        System.Array.Sort(éléments1)
        ' Visualización de la tabla 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
        ' Búsqueda
        While Not terminé
            ' pregunta
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' lectura y verificación de la respuesta
            réponse = Console.ReadLine().Trim()
            ' ¿Terminado?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificación
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' si no hay error
            If Not erreur Then
                ' se busca el elemento en la tabla ordenada
                i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
                ' Visualización de la respuesta
                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

Los resultados en pantalla son los siguientes:

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 primera parte del programa crea una matriz a partir de datos numéricos introducidos mediante el teclado. La matriz no puede dimensionarse de antemano, ya que se desconoce el número de elementos que introducirá el usuario. Por lo tanto, se trabaja con dos matrices: éléments1 y éléments2.


                ' nueva matriz para alojar el nuevo elemento
                éléments2 = New Double(i) {}
                ' copia de la tabla antigua a la nueva
                If i <> 0 Then
                    Array.Copy(éléments1, éléments2, i)
                End If
                ' la nueva tabla se convierte en la tabla anterior
                éléments1 = éléments2
                ' ya no se necesita la nueva tabla
                éléments2 = Nothing
                ' Inserción de un nuevo elemento
                éléments1(i) = élément
                ' un elemento más en la tabla
                i += 1

La tabla éléments1 contiene los valores introducidos actualmente. Cuando el usuario añade un nuevo valor, se crea una tabla éléments2 con un elemento más que éléments1, se copia el contenido de éléments1 en éléments2 (Array.Copy), se hace que éléments1 «apunte» a éléments2 y, por último, se añade el nuevo elemento a éléments1. Se trata de un proceso complejo que puede simplificarse si, en lugar de utilizar una matriz de tamaño fijo (Array), se utiliza una matriz de tamaño variable (ArrayList).

La matriz se ordena con el método Array.Sort. Este método se puede invocar con diferentes parámetros que especifican las reglas de ordenación. Sin parámetros, se realiza por defecto una ordenación ascendente. Por último, el método Array.BinarySearch permite buscar un elemento en una matriz ordenada.

4.5. La clase ArrayList

La clase ArrayList permite implementar tablas de tamaño variable durante la ejecución del programa, algo que no permite la clase Array anterior. Estas son algunas de las propiedades y métodos más comunes:

Public Sub New()
crea una lista vacía
Public Overridable ReadOnly Property Count
As Integer  Implements ICollection.Count
número de elementos de la colección
Public Overridable Function Add(ByVal value
As Object) As Integer Implements IList.Add
añade el objeto value al final de la colección
Public Overridable Sub Clear()
Implements IList.Clear
borra la lista
Overloads Public Overridable Function
IndexOf(ByVal value As Object) As Integer
Implements IList.IndexOf
índice del objeto value en la lista o -1 si no existe
Overloads Public Overridable Function
IndexOf(ByVal value As Object, ByVal startIndex
As Integer) As Integer
Lo mismo, pero buscando a partir del elemento n.º startIndex
Overloads Public Overridable Function
LastIndexOf(ByVal value As Object) As Integer
Lo mismo, pero devuelve el índice de la última aparición de «value» en la lista
Overloads Public Overridable Function
LastIndexOf(ByVal value As Object, ByVal startIndex As Integer) As Integer
Lo mismo, pero buscando a partir del elemento n.º startIndex
Public Overridable Sub Remove( ByVal obj As Object)
Implements IList.Remove
elimina el objeto obj si existe en la lista
Public Overridable Sub RemoveAt(ByVal index As Integer)
Implements IList.RemoveAt
elimina el elemento index de la lista
Overloads Public Overridable Function
BinarySearch(ByVal value As Object) As Integer
devuelve la posición del objeto «value» en la lista o -1 si no se encuentra en ella. La lista debe estar ordenada
Overloads Public Overridable Sub Sort()
ordena la lista. Esta debe contener objetos con una relación de orden predefinida (cadenas, números)
Overloads Public Overridable Sub
Sort(ByVal comparer As IComparer)
ordena la lista según la relación de orden establecida por la función comparar

Retomemos el ejemplo tratado con objetos de tipo Array y procesémoslo con objetos de tipo ArrayList:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections

Module test
    Sub Main()
        ' lectura de los elementos de una tabla introducidos mediante el 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é
            ' pregunta
            Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
            ' lectura de la respuesta
            réponse = Console.ReadLine().Trim()
            ' fin de la entrada si la cadena está vacía
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificación de la entrada
            Try
                élément = Double.Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' si no hay error
            If Not erreur Then
                ' un elemento más en la tabla
                éléments.Add(élément)
            End If
        End While
        ' visualización de la tabla sin ordenar
        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()
        ' visualización de la tabla 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
        ' Búsqueda
        While Not terminé
            ' pregunta
            Console.Out.Write("Elément cherché (rien pour arrêter) : ")
            ' lectura y verificación de la respuesta
            réponse = Console.ReadLine().Trim()
            ' ¿Terminado?
            If réponse.Equals("") Then
                Exit While
            End If
            ' verificación
            Try
                élément = [Double].Parse(réponse)
                erreur = False
            Catch
                Console.Error.WriteLine("Saisie incorrecte, recommencez")
                erreur = True
            End Try
            ' si no hay error
            If Not erreur Then
                ' se busca el elemento en la tabla ordenada
                i = éléments.BinarySearch(élément)
                ' Visualización de la respuesta
                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

Los resultados de la ejecución son los siguientes:

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 clase Hashtable

La clase Hashtable permite implementar un diccionario. Se puede considerar un diccionario como una tabla de dos columnas:

Las claves son únicas, c.a.d. no puede haber dos claves idénticas. Los principales métodos y propiedades de la clase Hashtable son los siguientes:

Public Sub New()
crea un diccionario vacío
Public Overridable Sub Add(ByVal key As
Object,ByVal value As Object)
Implements IDictionary.Add
añade una entrada (clave, valor) al diccionario, donde clave y valor son referencias a objetos.
Public Overridable Sub Remove
(ByVal key As Object) Implements IDictionary.Remove
elimina del diccionario la línea clave=key
Public Overridable Sub Clear()
Implements IDictionary.Clear
vacía el diccionario
Public Overridable Function ContainsKey
(ByVal key As Object) As Boolean
devuelve verdadero (true) si la clave key pertenece al diccionario.

Public Overridable Function
ContainsValue(ByVal value As Object) As Boolean
devuelve verdadero (true) si el valor value pertenece al diccionario.
Public Overridable ReadOnly Property
Count As Integer  Implements ICollection.Count
propiedad: número de elementos del diccionario (clave, valor)
Public Overridable ReadOnly Property
Keys As ICollection Implements IDictionary.Keys
propiedad: colección de claves del diccionario
Public Overridable ReadOnly Property
Values As ICollection Implements IDictionary.Values
propiedad: colección de valores del diccionario
Public Overridable Default Property
Item(ByVal key As Object) As Object  Implements IDictionary.Item
propiedad indexada: permite conocer o establecer el valor asociado a una clave

Consideremos el siguiente programa de ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
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}
        ' rellenar el diccionario
        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 en el diccionario
        Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
        ' lista de claves
        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 claves y 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
        ' se elimina la clave «paul»
        Console.Out.WriteLine("[Suppression d'une clé]")
        dico.Remove("paul")
        ' lista de claves y 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

        ' búsqueda en el diccionario
        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
            ' siguiente búsqueda
            Console.Out.Write("Nom recherché (rien pour arrêter) : ")
            nomCherché = Console.ReadLine().Trim()
        End While
    End Sub
End Module

Los resultados de la ejecución son los siguientes:

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

El programa también utiliza un objeto IEnumerator para recorrer las colecciones de claves y valores del diccionario de tipo ICollection (véanse más arriba las propiedades Keys y Values). Una colección es un conjunto de objetos que se puede recorrer. La interfaz ICollection se define de la siguiente manera:

Image

La propiedad Count nos permite conocer el número de elementos de la colección. La interfaz ICollection deriva de la interfaz IEnumerable:

Image

Esta interfaz solo tiene un método, GetEnumerator, que nos permite obtener un objeto de tipo IEnumerator:

Image

El método GetEnumerator() de una colección ICollection nos permite recorrer la colección con los siguientes métodos:

MoveNext
se sitúa en el siguiente elemento de la colección. Devuelve «true» si dicho elemento existe, y «false» en caso contrario. El primer MoveNext se sitúa en el primer elemento. El elemento «actual» de la colección está entonces disponible en la propiedad Current del enumerador
Current
propiedad: elemento actual de la colección
Reset
reposiciona el enumerador al inicio de la colección, c.a.d, antes del primer elemento.

La estructura de iteración sobre los elementos de una colección (ICollection) C es, por lo tanto, la siguiente:

' definir la colección
dim C as ICollection C=...
' obtener un enumerador de esta colección
dim itérateur as IEnumerator=C.GetEnumerator();
' recorrer la colección con este enumerador
while(itérateur.MoveNext())
    ' tenemos un elemento actual
    ' utilizar itérateur.Current
end while

4.7. La clase StreamReader

La clase StreamReader permite leer el contenido de un archivo. Estas son algunas de sus propiedades y métodos:

Public Sub New(ByVal path As String)
abre un flujo a partir del archivo path. Se lanza una excepción si este no existe
Overrides Public Sub Close()
cierra el flujo
Overrides Public Function ReadLine() As String
lee una línea del flujo abierto
Overrides Public Function ReadToEnd() As String
lee el resto del flujo desde la posición actual

He aquí un ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections
Imports System.IO

Module test
    Sub Main()
        Dim ligne As String = Nothing
        Dim fluxInfos As StreamReader = Nothing
        ' lectura del contenido del archivo
        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

y sus resultados de ejecución:

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 clase StreamWriter

La clase StreamWriter permite escribir en un archivo. Estas son algunas de sus propiedades y métodos:

Public Sub New(ByVal path As String)
abre un flujo de escritura a partir del archivo path. Se lanza una excepción si no se puede crear
Public Overridable Property AutoFlush
As Boolean
si es verdadero, la escritura en el flujo no pasa por un búfer; de lo contrario, la escritura en el flujo no es inmediata: primero se escribe en un búfer y luego en el flujo cuando el búfer está lleno. Por defecto se utiliza el modo con búfer. Es adecuado para flujos de archivo, pero generalmente no para flujos de red.
Public Overridable Property NewLine
As String
para establecer o conocer el carácter de fin de línea que debe utilizar el método WriteLine
Overrides Public Sub Close()
cierra el flujo
Overloads Public Overridable Sub
WriteLine(ByVal value As String)
escribe una línea en el flujo de escritura
Overrides Public Sub Flush()
escribe el búfer en el flujo

Consideremos el siguiente ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
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
            ' creación del archivo de texto
            fluxInfos = New StreamWriter("infos.txt")
            ' lectura de la línea introducida mediante el teclado
            Console.Out.Write("ligne (rien pour arrêter) : ")
            ligne = Console.In.ReadLine().Trim()
            ' bucle mientras la línea introducida no esté vacía
            While ligne <> ""
                ' escritura de la línea en el archivo de texto
                fluxInfos.WriteLine(ligne)
                ' lectura de una nueva línea del 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
            ' cierre del archivo
            Try
                fluxInfos.Close()
            Catch
            End Try
        End Try
    End Sub
End Module

y los resultados de la ejecución:

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 clase Regex

La clase Regex permite el uso de expresiones regulares. Estas permiten comprobar el formato de una cadena de caracteres. Así, se puede verificar que una cadena que representa una fecha tenga el formato dd/mm/aa. Para ello, se utiliza un patrón y se compara la cadena con dicho patrón. Así, en este ejemplo, d, m y a deben ser números. El patrón de un formato de fecha válido es entonces «\d\d/\d\d/\d\d», donde el símbolo \d designa un dígito. Los símbolos que se pueden utilizar en un patrón son los siguientes (documentación de Microsoft):

 
Descripción
\
Marca el carácter siguiente como carácter especial o literal. Por ejemplo, «n» corresponde al carácter «n». «\n» corresponde a un carácter de nueva línea. La secuencia «\\» corresponde a «\», mientras que «\»(» corresponde a «(».
^
Corresponde al inicio de la entrada.
$
Corresponde al final de la entrada.
*
Corresponde al carácter anterior cero o más veces. Así, «zo*» corresponde a «z» o a «zoo».
+
Corresponde al carácter anterior una o varias veces. Así, «zo+» corresponde a «zoo», pero no a «z».
?
Corresponde al carácter anterior cero o una vez. Por ejemplo, «a?ve?» corresponde a «ve» en «lever».
.
Coincide con cualquier carácter único, excepto el carácter de nueva línea.

(modèle)
Busca el modèle y memoriza la coincidencia. La subcadena correspondiente se puede extraer de la colección Matches obtenida, utilizando el elemento [0]...[n]. Para encontrar coincidencias con caracteres entre paréntesis ( ), utilice "\(" o "\)".

x|y
Corresponde a x o a y. Por ejemplo, «z|foot» corresponde a «z» o a «foot». «(z|f)oo» corresponde a «zoo» o a «foo».

{n}
n es un número entero no negativo. Corresponde exactamente a n multiplicado por el carácter. Por ejemplo, «o{2}» no corresponde a la «o» de «Bob», sino a las dos primeras «o» de «fooooot».

{n,}
n es un número entero no negativo. Corresponde al menos a n veces el carácter. Por ejemplo, «o{2,}» no coincide con la «o» de «Bob», sino con todas las «o» de «fooooot». «o{1,}» equivale a «o+» y «o{0,}» equivale a «o*».

{n,m}
m y n son números enteros no negativos. Corresponde al menos a n y como máximo a m veces el carácter. Por ejemplo, «o{1,3}» corresponde a las tres primeras «o» de «foooooot» y «o{0,1}» equivale a «o?».

[xyz]
Conjunto de caracteres. Corresponde a uno de los caracteres indicados. Por ejemplo, «[abc]» corresponde a «a» en «plat».

[^xyz]
Conjunto de caracteres negativo. Corresponde a cualquier carácter no indicado. Por ejemplo, «[^abc]» corresponde a «p» en «plat».

[a-z]
Rango de caracteres. Corresponde a cualquier carácter de la serie especificada. Por ejemplo, «[a-z]» corresponde a cualquier carácter alfabético minúsculo comprendido entre «a» y «z».

[^m-z]
Rango de caracteres negativo. Corresponde a cualquier carácter que no se encuentre en la serie especificada. Por ejemplo, «[^m-z]» corresponde a cualquier carácter que no se encuentre entre «m» y «z».
\b
Corresponde a un límite que representa una palabra, es decir, a la posición entre una palabra y un espacio. Por ejemplo, «er\b» corresponde a «er» en «lever», pero no a «er» en «verbe».
\B
Corresponde a un límite que no representa una palabra. «en*t\B» corresponde a «ent» en «bien entendu».
\d
Corresponde a un carácter que representa un número. Equivale a [0-9].
\D
Corresponde a un carácter que no representa un número. Equivale a [^0-9].
\f
Corresponde a un carácter de salto de página.
\n
Corresponde a un carácter de nueva línea.
\r
Corresponde a un carácter de retorno de carro.
\s
Corresponde a cualquier espacio en blanco, incluyendo el espacio, la tabulación, el salto de página, etc. Equivale a «[ \f\n\r\t\v]».
\S
Corresponde a cualquier carácter de espacio no en blanco. Equivale a «[^ \f\n\r\t\v]».
\t
Corresponde a un carácter de tabulación.
\v
Corresponde a un carácter de tabulación vertical.
\w
Corresponde a cualquier carácter que represente una palabra e incluya un guión bajo. Equivale a «[A-Za-z0-9_]».
\W
Corresponde a cualquier carácter que no represente una palabra. Equivale a «[^A-Za-z0-9_]».

\num
Corresponde a num, donde num es un número entero positivo. Hace referencia a las coincidencias memorizadas. Por ejemplo, «(.)\1» corresponde a dos caracteres idénticos consecutivos.

\n
Corresponde a n, donde n es un valor de escape octal. Los valores de escape octales deben tener 1, 2 o 3 dígitos. Por ejemplo, «\11» y «\011» corresponden ambos a un carácter de tabulación. «\0011» equivale a «\001» y «1». Los valores de escape octales no deben superar 256. Si fuera así, solo se tendrían en cuenta los dos primeros dígitos en la expresión. Permite utilizar los códigos ASCII en expresiones regulares.

\xn
Corresponde a n, donde n es un valor de escape hexadecimal. Los valores de escape hexadecimales deben constar obligatoriamente de dos dígitos. Por ejemplo, «\x41» corresponde a «A». «\x041» equivale a «\x04» y «1». Permite utilizar los códigos ASCII en expresiones regulares.

Un elemento de una plantilla puede aparecer una o varias veces. Veamos algunos ejemplos relacionados con el símbolo \d, que representa un dígito:

plantilla
significado
\d
un dígito
\d?
0 o 1 dígito
\d*
0 o más dígitos
\d+
1 o más dígitos
\d{2}
2 dígitos
\d{3,}
al menos 3 dígitos
\d{5,7}
entre 5 y 7 dígitos

Imaginemos ahora el modelo capaz de describir el formato esperado para una cadena de caracteres:

cadena buscada
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
  

Se puede especificar dónde se busca el patrón en la cadena:

patrón
significado
^modèle
el patrón comienza la cadena
modèle$
el modelo termina la cadena
^modèle$
la plantilla comienza y termina la cadena
modèle
el patrón se busca en toda la cadena, comenzando por el principio de la misma.
cadena buscada
patrón
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

Los subconjuntos de un patrón pueden «recuperarse». De este modo, no solo se puede comprobar si una cadena se ajusta a un patrón concreto, sino que también se pueden extraer de dicha cadena los elementos que corresponden a los subconjuntos del patrón que se han rodeado de paréntesis. Así, si se analiza una cadena que contiene una fecha dd/mm/aa y se desea además recuperar los elementos dd, mm, aa de dicha fecha, se utilizará el patrón (\d\d)/(\d\d)/(\d\d).

4.9.1. Comprobar que una cadena se ajusta a un patrón dado

Un objeto de tipo Regex se construye de la siguiente manera:

Public Sub New(ByVal pattern As String)

El constructor crea un objeto «expresión regular» a partir de un patrón pasado como parámetro (pattern). Una vez construida la expresión regular modelo, se puede comparar con cadenas de caracteres mediante el método IsMatch:

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

IsMatch devuelve verdadero si la cadena de entrada coincide con el patrón de la expresión regular. A continuación se muestra un ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex1

    Sub Main()
        ' una expresión regular de patrón
        Dim modèle1 As String = "^\s*\d+\s*$"
        Dim regex1 As New Regex(modèle1)
        ' comparar un ejemplar con el patrón
        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

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

y los resultados de la ejecución:

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. Buscar todos los elementos de una cadena que coincidan con un patrón

El método Matches

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

devuelve una colección de elementos de la cadena input que coinciden con el patrón, tal y como se muestra en el siguiente ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' varias ocurrencias del patrón en el ejemplo
        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

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

La clase MatchCollection tiene una propiedad Count que es el número de elementos de la colección. Si résultats es un objeto MatchCollection, résultats(i) es el elemento i de esta colección y es de tipo Match. En nuestro ejemplo, résultats es el conjunto de elementos de la cadena exemplaire3 que corresponden al modelo modèle2, y résultats(i) es uno de esos elementos. La clase Match tiene dos propiedades que nos interesan aquí:

  • Value: el valor del objeto Match, es decir, el elemento correspondiente al modelo
  • Index: la posición en la que se ha encontrado el elemento en la cadena explorada

Resultados de la ejecución del 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 un patrón

Se pueden «extraer» subconjuntos de un patrón. De este modo, no solo se puede comprobar si una cadena se ajusta a un patrón concreto, sino que también se pueden extraer de dicha cadena los elementos correspondientes a los subconjuntos del patrón que se han rodeado de paréntesis. Así, si se analiza una cadena que contiene una fecha dd/mm/aa y se desea además extraer los elementos dd, mm y aa de dicha fecha, se utilizará el patrón (\d\d)/(\d\d)/(\d\d). Veamos el siguiente ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions

Module regex2
    Sub Main()
        ' captura de elementos en la plantilla
        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"
        ' verificación de la plantilla
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' la copia se ajusta a la plantilla
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' se muestran los 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
            ' el ejemplar no se corresponde con el modelo
            affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
        End If
    End Sub

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

La ejecución de este programa produce los siguientes 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

La novedad se encuentra en la siguiente parte del código:


        ' verificación del modelo
        Dim résultat As Match = regex3.Match(exemplaire4)
        If résultat.Success Then
            ' el ejemplar se corresponde con el modelo
            affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
            ' se muestran los 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

La cadena exemplaire4 se compara con el modelo regex3 mediante el método Match. Este devuelve un objeto Match ya presentado. Aquí utilizamos dos nuevas propiedades de esta clase:

  • Success: indica si ha habido coincidencia
  • Groups: colección en la que
    • Groups[0] corresponde a la parte de la cadena que se ajusta al patrón
    • Groups[i] (i>=1) corresponde al grupo de paréntesis n.º i

Si el resultado es del tipo Match, résultats.Groups es del tipo GroupCollection y résultats.Groups[i] es del tipo Group. La clase Group tiene dos propiedades que utilizamos aquí:

  • Value: el valor del objeto Group que contiene el elemento correspondiente al contenido de un paréntesis
  • Index: la posición en la que se ha encontrado el elemento en la cadena explorada

4.9.4. Un programa de aprendizaje

Encontrar la expresión regular que nos permita verificar que una cadena se ajusta a un determinado patrón es, a veces, todo un reto. El siguiente programa permite practicar. Solicita un patrón y una cadena y, a continuación, indica si la cadena se ajusta o no al patrón.


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic

Module regex4
    Sub Main()
        ' una expresión regular de plantilla
        Dim modèle, chaine As String
        Dim regex As Regex = Nothing
        Dim résultats As MatchCollection
        ' se solicita al usuario los modelos y los ejemplares que se deben comparar con este
        Dim terminé1 As Boolean = False
        Do While Not terminé1
            Dim erreur As Boolean = True
            Do While Not terminé1 And erreur
                ' se solicita el patrón
                Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
                modèle = Console.In.ReadLine()
                ' ¿Terminado?
                If modèle.Trim().ToLower() = "fin" Then
                    terminé1 = True
                Else
                    ' se crea la expresión regular
                    Try
                        regex = New Regex(modèle)
                        erreur = False
                    Catch ex As Exception
                        Console.Error.WriteLine(("Erreur : " + ex.Message))
                    End Try
                End If
            Loop
            ' ¿Terminado?
            If terminé1 Then Exit Sub
            ' se le pide al usuario los ejemplares que se van a comparar con el 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()
                ' ¿Terminado?
                If chaine.Trim().ToLower() = "fin" Then
                    terminé2 = True
                Else
                    ' se realiza la comparación
                    résultats = regex.Matches(chaine)
                    ' ¿Éxito?
                    If résultats.Count = 0 Then
                        Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
                    Else
                        ' se muestran los elementos que coinciden con el 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

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

He aquí un ejemplo de ejecución:

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. El método Split

Ya hemos visto este método en la clase String:

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

La cadena se considera una secuencia de campos separados por los caracteres presentes en la tabla [separator]. El resultado es la tabla de dichos campos.

El separador de campos de la cadena es aquí uno de los caracteres de la tabla separator. El método Split de la clase Regex nos permite expresar el separador en función de un patrón:

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

La cadena [input] se descompone en campos, separados por un separador que se ajusta al modelo del objeto Regex actual. Supongamos, por ejemplo, que tenemos en un archivo de texto líneas con el formato campo1, campo2, ..., campo n. Los campos están separados por una coma, pero esta puede ir precedida o seguida de espacios. El método Split de la clase string no es adecuado en este caso. El método RegEx ofrece la solución. Si línea es la línea leída, los campos se pueden obtener mediante

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

tal y como se muestra en el siguiente ejemplo:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Text.RegularExpressions

Module regex5
    Sub Main()
        ' una línea
        Dim ligne As String = "abc  , def  , ghi"
        ' una plantilla
        Dim modèle As New Regex("\s*,\s*")
        ' desglose de línea en campos
        Dim champs As String() = modèle.Split(ligne)
        ' visualización
        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 de la ejecución:

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. Las clases BinaryReader y BinaryWriter

Las clases BinaryReader y BinaryWriter sirven para leer y escribir archivos binarios. Consideremos la siguiente aplicación. Queremos escribir un programa que se llamaría de la siguiente manera:

// sintaxis pg texto bin
// se lee un archivo de texto (texto) y se almacena su contenido en un
// archivo binario
// El archivo de texto contiene líneas con el formato nombre: edad
// que se almacenarán en una estructura de tipo string, int

El archivo de texto tiene el siguiente contenido:

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

El programa es el siguiente:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

' BinaryWriter()

Module bw1
    ' sintaxis pg texto bin
    ' se lee un archivo de texto (texto) y se almacena su contenido en un
    ' archivo binario
    ' el archivo de texto tiene líneas con el formato nombre : edad
    ' que se almacenarán en una estructura string, int

    Sub Main(ByVal arguments() As String)
        ' se necesitan 2 argumentos
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg texte binaire")
            Environment.Exit(1)
        End If
        ' apertura del archivo de texto en modo lectura
        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 archivo binario en modo escritura
        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
        ' lectura del archivo de texto - escritura del archivo binario
        ' línea del archivo de texto
        Dim ligne As String
        ' separador de campos de la línea
        Dim séparateur As New Regex("\s*:\s*")
        ' el formato de la edad
        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
            ' ¿línea vacía?
            If ligne.Trim() = "" Then
                traitementFini = True
            End If
            ' una línea más
            If Not traitementFini Then
                numLigne += 1
                ' una línea nombre: edad
                champs = séparateur.Split(ligne)
                ' necesitamos 2 campos
                If champs.Length <> 2 Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
                    ' línea siguiente
                    traitementFini = True
                End If
            End If
            If Not traitementFini Then
                ' el segundo campo debe ser un entero >=0
                If Not modAge.IsMatch(champs(1)) Then
                    Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
                    ' línea siguiente
                    traitementFini = True
                End If
                ' escribimos los datos en el archivo binario
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))
            End If
            'línea siguiente
            ligne = input.ReadLine()
        End While
        ' cierre de los archivos
        input.Close()
        output.Close()
    End Sub
End Module

Centrémonos en las operaciones relacionadas con la clase BinaryWriter:

  • el objeto BinaryWriter se abre mediante la operación

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

El argumento del constructor debe ser un flujo (Stream). En este caso, se trata de un flujo creado a partir de un archivo (FileStream) del que se proporciona:

  • (continuación)
    • el nombre
    • la operación a realizar, aquí FileMode.Create para crear el archivo
    • el tipo de acceso, en este caso FileAccess.Write para un acceso de escritura al archivo
  • la operación de escritura

                ' se escriben los datos en el archivo binario
                output.Write(champs(0))
                output.Write(Integer.Parse(champs(1)))

La clase BinaryWriter dispone de diferentes métodos Write sobrecargados para escribir los diferentes tipos de datos simples

  • la operación de cierre del flujo
        output.Close()

Los resultados de la ejecución anterior nos los proporcionará el siguiente programa. Este también acepta dos argumentos:

    ' sintaxis pg bin texto
    ' se lee un archivo binario bin y se guarda su contenido en un archivo de texto (texto)
    ' el archivo binario tiene una estructura string, int
    ' el archivo de texto tiene líneas con el formato nombre : edad

Por lo tanto, realizamos la operación inversa. Leemos un archivo binario para crear un archivo de texto. Si el archivo de texto resultante es idéntico al archivo original, sabremos que la conversión texto --> binario --> texto se ha realizado correctamente. El código es el siguiente:


' opciones
Option Strict On
Option Explicit On 

' espacios de nombres
Imports System
Imports System.Text.RegularExpressions
Imports System.IO

Module br1
    ' sintaxis pg bin texto
    ' se lee un archivo binario bin y se guarda su contenido en un archivo de texto (texto)
    ' el archivo binario tiene una estructura string, int
    ' el archivo de texto tiene líneas con el formato nombre : edad

    Sub Main(ByVal arguments() As String)
        ' se necesitan 2 argumentos
        Dim nbArgs As Integer = arguments.Length
        If nbArgs <> 2 Then
            Console.Error.WriteLine("syntaxe : pg binaire texte")
            Environment.Exit(1)
        End If
        ' apertura del archivo binario en modo lectura
        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 archivo de texto en modo escritura
        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
        ' lectura del archivo binario - escritura del archivo de texto
        Dim nom As String        ' nom d'une personne
        Dim age As Integer        ' son âge
        ' bucle de procesamiento del archivo binario
        While True
            ' lectura del nombre
            Try
                nom = dataIn.ReadString()
            Catch
                ' fin del archivo
                Exit Sub
            End Try
            ' lectura de edad
            Try
                age = dataIn.ReadInt32()
            Catch
                Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
                Exit Sub
            End Try
            ' escritura en archivo de texto
            dataOut.WriteLine(nom & ":" & age)
            System.Console.WriteLine(nom & ":" & age)
        End While
        ' se cierra todo
        dataIn.Close()
        dataOut.Close()
    End Sub
End Module

Centrémonos en las operaciones relacionadas con la clase BinaryReader:

  • el objeto BinaryReader se abre mediante la operación

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

El argumento del constructor debe ser un flujo (Stream). En este caso, se trata de un flujo creado a partir de un archivo (FileStream) del que se proporciona:

  • (continuación)
    • el nombre
    • la operación a realizar, aquí FileMode.Open para abrir un archivo existente
    • el tipo de acceso, en este caso FileAccess.Read para un acceso de lectura al archivo
  • la operación de lectura
                nom = dataIn.ReadString()
                age = dataIn.ReadInt32()

La clase BinaryReader dispone de diferentes métodos ReadXX para leer los diferentes tipos de datos simples

  • la operación de cierre del flujo
        dataIn.Close()

Si se ejecutan los dos programas en cadena, transformando personnes.txt en personnes.bin y luego personnes.bin en personnes.txt2, se obtiene:

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