4. Powszechnie używane klasy .NET
Poniżej przedstawiamy kilka interesujących klas platformy .NET, które mogą zainteresować nawet początkujących użytkowników. Najpierw pokażemy, jak uzyskać informacje na temat setek dostępnych klas.
4.1. Szukanie pomocy w SDK.NET
4.1.1. wincv
Jeśli zainstalowano tylko SDK, a nie Visual Studio.NET, można skorzystać z programu wincv.exe, który zazwyczaj znajduje się w drzewie katalogów zestawu SDK, na przykład w lokalizacji C:\Program Files\Microsoft Visual Studio.NET 2003\SDK\v1.1. Po uruchomieniu tego narzędzia wyświetla się następujący interfejs:
![]() |
W polu (1) wpisujemy nazwę żądanej klasy. Spowoduje to wyświetlenie w polu (2) różnych możliwych tematów. Wybieramy odpowiedni i otrzymujemy wynik w polu (3) – w tym przypadku klasę HashTable. Ta metoda sprawdza się, jeśli znamy nazwę klasy, której szukamy. Jeśli chcemy przejrzeć listę możliwości oferowanych przez platformę .NET, można skorzystać z pliku HTML StartHere.htm, który również znajduje się bezpośrednio w folderze instalacyjnym SSK.Net, na przykład C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.

Aby uzyskać ogólny przegląd klas .NET Framework SDK Documentation, należy kliknąć poniższy link:

W tym miejscu należy kliknąć link [Bibliothèque de classes]. Znajduje się tam lista wszystkich klas .NET:

Kliknijmy na przykład link System.Collections. Ta przestrzeń nazw zawiera różne klasy implementujące kolekcje, w tym klasę HashTable:

Przejdźmy do poniższego linku HashTable:

Otrzymujemy następującą stronę:

Zwróćmy uwagę na położenie kursora poniżej. Wskazuje on na link umożliwiający wybranie żądanego języka, w tym przypadku Visual Basic.
Znajduje się tam prototyp klasy oraz przykłady jej zastosowania. Kliknijmy poniższy link [Hashtable, membres]:

Otrzymujemy pełny opis klasy:

Ta metoda jest najlepsza do zapoznania się z SDK i jego klasami. Narzędzie WinCV okazuje się przydatne, gdy znamy już nieco daną klasę, ale zapomnieliśmy niektórych jej elementów składowych. WinCV pozwala wówczas szybko odnaleźć klasę i jej elementy składowe.
4.2. Szukanie pomocy dotyczącej klas za pomocą VS.NET
Poniżej przedstawiamy kilka wskazówek dotyczących wyszukiwania pomocy w programie Visual Studio.NET
4.2.1. Opcja Pomoc
Wybierzmy opcję [?] z menu.

Pojawi się następujące okno:

Z listy rozwijanej można wybrać filtr pomocy. W tym przypadku wybierzemy filtr [Visual Basic].

Przydatne są dwie instrukcje:
- pomoc dotycząca samego języka VB.NET (składnia)
- pomoc dotycząca elementów classes.NET, które można wykorzystać w języku VB.NET
Pomoc dotycząca języka VB.NET jest dostępna poprzez [Visual Studio.NET/Visual Basic et Visual C#/Reference/Visual Basic]:

Wyświetla się następująca strona pomocy:

Stąd, dzięki różnym podsekcjom, możemy uzyskać pomoc dotyczącą różnych zagadnień związanych z VB.NET. Zwróćmy uwagę na samouczki dotyczące VB.NET:

Aby uzyskać dostęp do różnych klas platformy .NET, należy wybrać pomoc [Visual Studio.NET/.NET Framework].

Zwróćmy szczególną uwagę na sekcję [Référence/Bibliothèque de classes]:

Załóżmy, że interesuje nas klasa [ArrayList]. Znajduje się ona w przestrzeni nazw [System.Collections]. Należy o tym wiedzieć, w przeciwnym razie lepiej skorzystać z metody wyszukiwania opisanej poniżej. Otrzymujemy następującą pomoc:

Link [ArrayList, classe] zawiera ogólny opis klasy:

Tego typu strona istnieje dla wszystkich klas. Zawiera ona podsumowanie klasy wraz z przykładami. Aby zapoznać się z opisem elementów tej klasy, należy kliknąć link [ArrayList, membres]:

4.2.2. Pomoc/Indeks

Opcja [Aide/index] pozwala na wyszukiwanie pomocy bardziej ukierunkowanej niż poprzednia. Wystarczy wpisać szukane słowo kluczowe:

Zaletą tej metody w porównaniu z poprzednią jest to, że nie trzeba wiedzieć, gdzie w systemie pomocy znajduje się poszukiwana informacja. Jest to prawdopodobnie metoda preferowana w przypadku wyszukiwania ukierunkowanego, podczas gdy druga metoda jest bardziej odpowiednia do zapoznania się z całą zawartością pomocy.
4.3. Klasa String
Klasa String posiada wiele właściwości i metod. Oto kilka z nich:
liczba znaków w ciągu | |
domyślna właściwość indeksowana. [String].Chars(i) to znak o numerze i w ciągu | |
zwraca wartość true, jeśli ciąg kończy się wartością | |
zwraca wartość logiczną „prawda”, jeśli ciąg znaków zaczyna się od wartości | |
zwraca wartość logiczną „prawda”, jeśli ciąg znaków jest równy wartości | |
zwraca pierwszą pozycję ciągu w ciągu „value” – wyszukiwanie rozpoczyna się od znaku nr 0 | |
zwraca pierwszą pozycję w ciągu znaków o wartości „value” – wyszukiwanie rozpoczyna się od znaku nr startIndex | |
metoda klasy – zwraca ciąg znaków będący wynikiem połączenia wartości z tablicy value z separatorem separator | |
zwraca kopię bieżącego ciągu znaków, w której znak oldChar został zastąpiony znakiem newChar | |
ciąg znaków jest traktowany jako sekwencja pól oddzielonych znakami zawartymi w tablicy separator. Wynikiem jest tablica tych pól | |
podciąg bieżącego ciągu, zaczynający się w pozycji startIndex i zawierający length znaków | |
zamienia bieżący ciąg na małe litery | |
zamienia bieżący ciąg znaków na wielkie litery | |
usuwa spacje na początku i na końcu bieżącego ciągu znaków |
Ciąg znaków C można traktować jako tablicę znaków. Zatem
- C.Chars(i) oznacza znak i z C
- C.Length to liczba znaków w ciągu C
Rozważmy następujący przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
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
' wyświetla
Sub affiche(ByVal msg As [String])
' wyświetla komunikat
Console.Out.WriteLine(msg)
End Sub
End Module
Wykonanie daje następujące wyniki:
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]
Rozważmy nowy przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Module string2
Sub Main()
' analizowana linia
Dim ligne As String = "un:deux::trois:"
' separatory pól
Dim séparateurs() As Char = {":"c}
' podział
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
' łączenie
Console.Out.WriteLine(("join=[" + System.String.Join(":", champs) + "]"))
End Sub
End Module
oraz wyniki wykonania:
Metoda Split klasy String pozwala umieścić pola ciągu znaków w tablicy. Definicja tej metody jest następująca:
tablica znaków. Znaki te odpowiadają znakom używanym do oddzielania pól w ciągu znaków. Jeśli więc ciąg znaków to [champ1, champ2, champ3], można użyć separatora: separator=new char() {","c}. Jeśli separatorem jest ciąg spacji, należy użyć separator=nothing. | |
tablica ciągów znaków, w której każdy element jest polem ciągu znaków. |
Metoda Join jest metodą statyczną klasy String:
tablica ciągów znaków | |
ciąg znaków, który będzie służył jako separator pól | |
ciąg znaków utworzony przez połączenie elementów tablicy value, oddzielonych ciągiem separator. |
4.4. Klasa Array
Klasa Array implementuje tablicę. W naszym przykładzie wykorzystamy następujące właściwości i metody:
właściwość – liczba elementów tablicy | |
metoda klasy – zwraca pozycję value w posortowanej tablicy array – wyszukuje od pozycji index i z length elementami | |
metoda klasy – kopiuje elementy z length do destinationArray z sourceArray – przy tej okazji tworzony jest destinationArray | |
metoda klasy – sortuje tablicę array – musi ona zawierać typ danych posiadający domyślną funkcję porządkowania (ciągi znaków, liczby). |
Poniższy program ilustruje wykorzystanie klasy Array:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Module test
Sub Main()
' odczyt elementów tablicy wprowadzonych z klawiatury
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é
' pytanie
Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
' odczyt odpowiedzi
réponse = Console.ReadLine().Trim()
' zakończenie wprowadzania danych, jeśli ciąg znaków jest pusty
If réponse.Equals("") Then
Exit While
End If
' sprawdzanie wprowadzonych danych
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' jeśli nie ma błędu
If Not erreur Then
' nowa tablica na nowy element
éléments2 = New Double(i) {}
' kopiowanie starej tablicy do nowej tablicy
If i <> 0 Then
Array.Copy(éléments1, éléments2, i)
End If
' nowa tablica staje się starą tablicą
éléments1 = éléments2
' nowa tablica nie jest już potrzebna
éléments2 = Nothing
' wstawienie nowego elementu
éléments1(i) = élément
' jeden element więcej w tabeli
i += 1
End If
End While
' wyświetlenie tabeli nieposortowanej
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
' sortowanie tabeli
System.Array.Sort(éléments1)
' wyświetlanie posortowanej tabeli
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
' Wyszukiwanie
While Not terminé
' pytanie
Console.Out.Write("Elément cherché (rien pour arrêter) : ")
' odczyt i weryfikacja odpowiedzi
réponse = Console.ReadLine().Trim()
' koniec?
If réponse.Equals("") Then
Exit While
End If
' weryfikacja
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' jeśli nie ma błędu
If Not erreur Then
' szukamy elementu w posortowanej tablicy
i = System.Array.BinarySearch(éléments1, 0, éléments1.Length, élément)
' Wyświetlanie odpowiedzi
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
Wyniki wyświetlane na ekranie są następujące:
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) :
W pierwszej części programu tworzona jest tablica na podstawie danych liczbowych wprowadzonych z klawiatury. Nie można z góry określić rozmiaru tablicy, ponieważ nie wiadomo, ile elementów wprowadzi użytkownik. Pracujemy zatem z dwiema tablicami: éléments1 i éléments2.
' nowa tablica na nowy element
éléments2 = New Double(i) {}
' kopiowanie starej tablicy do nowej tablicy
If i <> 0 Then
Array.Copy(éléments1, éléments2, i)
End If
' nowa tabela staje się starą tabelą
éléments1 = éléments2
' nowa tabela nie jest już potrzebna
éléments2 = Nothing
' wstawienie nowego elementu
éléments1(i) = élément
' jeden element więcej w tabeli
i += 1
Tablica éléments1 zawiera aktualnie wprowadzone wartości. Gdy użytkownik dodaje nową wartość, tworzy się tablicę éléments2, która ma o jeden element więcej niż éléments1, kopiuje się zawartość tabeli éléments1 do tabeli éléments2 (Array.Copy), ustawia się „odwołanie” tablicy éléments1 do tablicy éléments2, a na koniec dodaje się nowy element do tablicy éléments1. Jest to złożony proces, który można uprościć, jeśli zamiast tablicy o stałym rozmiarze (Array) użyje się tablicy o zmiennym rozmiarze (ArrayList).
Tablica jest sortowana za pomocą metody Array.Sort. Metodę tę można wywołać z różnymi parametrami określającymi reguły sortowania. Bez parametrów domyślnie wykonywane jest sortowanie w porządku rosnącym. Wreszcie metoda Array.BinarySearch umożliwia wyszukiwanie elementu w posortowanej tablicy.
4.5. Klasa ArrayList
Klasa ArrayList umożliwia implementację tablic o zmiennej wielkości w trakcie wykonywania programu, czego nie pozwala poprzednia klasa Array. Oto niektóre z typowych właściwości i metod:
tworzy pustą listę | |
liczba elementów w kolekcji | |
dodaje obiekt „value” na końcu kolekcji | |
usuwa listę | |
indeks elementu „value” na liście lub -1, jeśli nie istnieje | |
to samo, ale wyszukiwanie rozpoczyna się od elementu o numerze startIndex | |
to samo, ale zwraca indeks ostatniego wystąpienia wartości na liście | |
to samo, ale wyszukiwanie rozpoczyna się od elementu nr startIndex | |
usuń obiekt obj, jeśli występuje na liście | |
usuwa element o indeksie z listy | |
zwraca pozycję obiektu „value” na liście lub -1, jeśli go tam nie ma. Lista musi być posortowana | |
sortuje listę. Lista ta musi zawierać obiekty o z góry zdefiniowanej relacji porządkowej (ciągi znaków, liczby) | |
sortuje listę zgodnie z relacją porządkową ustaloną przez funkcję porównującą |
Wróćmy do przykładu z obiektami typu Array i przetwórzmy go z wykorzystaniem obiektów typu ArrayList:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Module test
Sub Main()
' odczyt elementów tablicy wpisanych z klawiatury
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é
' pytanie
Console.Out.Write(("Elément (réel) " & i & " du tableau (rien pour terminer) : "))
' odczyt odpowiedzi
réponse = Console.ReadLine().Trim()
' zakończenie wprowadzania danych, jeśli ciąg znaków jest pusty
If réponse.Equals("") Then
Exit While
End If
' sprawdzanie wprowadzonych danych
Try
élément = Double.Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' jeśli nie ma błędu
If Not erreur Then
' kolejny element w tablicy
éléments.Add(élément)
End If
End While
' wyświetlenie tablicy nieposortowanej
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()
' wyświetlanie posortowanej tablicy
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
' Wyszukiwanie
While Not terminé
' pytanie
Console.Out.Write("Elément cherché (rien pour arrêter) : ")
' odczyt i weryfikacja odpowiedzi
réponse = Console.ReadLine().Trim()
' koniec?
If réponse.Equals("") Then
Exit While
End If
' weryfikacja
Try
élément = [Double].Parse(réponse)
erreur = False
Catch
Console.Error.WriteLine("Saisie incorrecte, recommencez")
erreur = True
End Try
' jeśli nie ma błędu
If Not erreur Then
' szukamy elementu w posortowanej tablicy
i = éléments.BinarySearch(élément)
' Wyświetlanie odpowiedzi
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
Wyniki wykonania są następujące:
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. Klasa Hashtable
Klasa Hashtable umożliwia implementację słownika. Słownik można postrzegać jako tablicę o dwóch kolumnach:
![]() |
Klucze są unikalne, c.a.d, co oznacza, że nie mogą występować dwa identyczne klucze. Główne metody i właściwości klasy Hashtable są następujące:
tworzy pusty słownik | |
dodaje wiersz (key, value) do słownika, gdzie key i value są odwołaniami do obiektów. | |
usuwa z słownika wiersz o kluczu=key | |
opróżnia słownik | |
zwraca wartość true, jeśli klucz key znajduje się w słowniku. | |
zwraca wartość true, jeśli wartość value znajduje się w słowniku. | |
właściwość: liczba elementów słownika (klucz, wartość) | |
właściwość: zbiór kluczy słownika | |
właściwość: zbiór wartości słownika | |
właściwość indeksowana: pozwala sprawdzić lub ustawić wartość powiązaną z kluczem key |
Rozważmy następujący przykładowy program:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
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}
' wypełnianie słownika
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
' liczba elementów w słowniku
Console.Out.WriteLine(("Le dictionnaire a " & dico.Count & " éléments"))
' lista kluczy
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 wartości
Console.Out.WriteLine("[Liste des valeurs]")
Dim valeurs As IEnumerator = dico.Values.GetEnumerator()
While valeurs.MoveNext()
Console.Out.WriteLine(valeurs.Current)
End While
' lista kluczy i wartości
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
' usuwamy klucz „paul”
Console.Out.WriteLine("[Suppression d'une clé]")
dico.Remove("paul")
' lista kluczy i wartości
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
' wyszukiwanie w słowniku
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
' kolejne wyszukiwanie
Console.Out.Write("Nom recherché (rien pour arrêter) : ")
nomCherché = Console.ReadLine().Trim()
End While
End Sub
End Module
Wyniki wykonania są następujące:
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) :
Program wykorzystuje również obiekt IEnumerator do przeglądania zbiorów kluczy i wartości słownika typu ICollection (patrz powyżej właściwości Keys i Values). Kolekcja to zbiór obiektów, po którym można przeglądać. Interfejs ICollection jest zdefiniowany w następujący sposób:

Właściwość Count pozwala nam poznać liczbę elementów w kolekcji. Interfejs ICollection wywodzi się z interfejsu IEnumerable:

Ten interfejs posiada tylko jedną metodę GetEnumerator, która pozwala uzyskać obiekt typu IEnumerator:

Metoda GetEnumerator() kolekcji ICollection pozwala nam przeglądać kolekcję za pomocą następujących metod:
przechodzi do następnego elementu kolekcji. Zwraca wartość true, jeśli ten element istnieje, w przeciwnym razie false. Pierwsza metoda MoveNext przechodzi do pierwszego elementu. „Bieżący” element kolekcji jest wówczas dostępny we właściwości Current iteratora | |
właściwość: bieżący element kolekcji | |
przesuwa wskaźnik na początek kolekcji, c.a.d, przed pierwszy element. |
Struktura iteracji nad elementami kolekcji (ICollection) w języku C wygląda zatem następująco:
' zdefiniowanie kolekcji
dim C as ICollection C=...
' pobierz wskaźnik tej kolekcji
dim itérateur as IEnumerator=C.GetEnumerator();
' przeglądanie kolekcji za pomocą tego indeksatora
while(itérateur.MoveNext())
' mamy bieżący element
' wykorzystać itérateur.Current
end while
4.7. Klasa StreamReader
Klasa StreamReader umożliwia odczytanie zawartości pliku. Oto niektóre z jej właściwości i metod:
otwiera strumień z pliku path. Jeśli plik nie istnieje, zgłaszany jest wyjątek | |
zamyka strumień | |
odczytuje wiersz z otwartego strumienia | |
odczytuje pozostałą część strumienia od bieżącej pozycji |
Oto przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Imports System.IO
Module test
Sub Main()
Dim ligne As String = Nothing
Dim fluxInfos As StreamReader = Nothing
' odczyt zawartości pliku
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
oraz wyniki jego wykonania:
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. Klasa StreamWriter
Klasa StreamWriter umożliwia zapisywanie danych do pliku. Oto niektóre z jej właściwości i metod:
otwiera strumień zapisu z pliku path. Jeśli nie da się go utworzyć, zgłaszany jest wyjątek | |
jeśli wartość jest równa true, zapis do strumienia odbywa się bez buforowania; w przeciwnym razie zapis do strumienia nie następuje natychmiast: najpierw dane są zapisywane do bufora, a dopiero gdy bufor się zapełni, trafiają do strumienia. Domyślnie używany jest tryb buforowany. Nadaje się on dobrze do strumieni plików, ale zazwyczaj nie do strumieni sieciowych. | |
aby ustawić lub sprawdzić znak końca linii, który ma być używany przez metodę WriteLine | |
zamyka strumień | |
zapisuje wiersz w strumieniu zapisu | |
zapisuje zawartość bufora do strumienia |
Rozważmy następujący przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
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
' tworzenie pliku tekstowego
fluxInfos = New StreamWriter("infos.txt")
' odczyt wiersza wprowadzonego z klawiatury
Console.Out.Write("ligne (rien pour arrêter) : ")
ligne = Console.In.ReadLine().Trim()
' pętla, dopóki wprowadzony wiersz nie jest pusty
While ligne <> ""
' zapis wiersza do pliku tekstowego
fluxInfos.WriteLine(ligne)
' odczyt nowego wiersza z klawiatury
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
' zamknięcie pliku
Try
fluxInfos.Close()
Catch
End Try
End Try
End Sub
End Module
oraz wyniki wykonania:
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. Klasa Regex
Klasa Regex umożliwia stosowanie wyrażeń regularnych. Pozwalają one na sprawdzanie formatu ciągu znaków. Dzięki temu można zweryfikować, czy ciąg znaków reprezentujący datę ma format dd/mm/rr. W tym celu wykorzystuje się wzorzec i porównuje się ciąg znaków z tym wzorcem. W tym przykładzie znaki j, m i a muszą być cyframi. Szablon prawidłowego formatu daty to zatem „\d\d/\d\d/\d\d”, gdzie symbol \d oznacza cyfrę. Symbole, których można używać w szablonie, są następujące (dokumentacja Microsoft):
Opis | |
Oznacza następny znak jako znak specjalny lub dosłowny. Na przykład „n” odpowiada znakowi „n”. „\n” odpowiada znakowi nowego wiersza. Sekwencja „\\” odpowiada znakowi „\”, natomiast „\(" odpowiada znakowi „(”. | |
Odpowiada początkowi wprowadzania tekstu. | |
Odpowiada końcowi wpisu. | |
Odpowiada poprzedniemu znakowi zero lub więcej razy. Tak więc „zo*” odpowiada „z” lub „zoo”. | |
Odpowiada poprzedniemu znakowi jeden lub więcej razy. Tak więc „zo+” odpowiada „zoo”, ale nie odpowiada „z”. | |
Odpowiada poprzedniemu znakowi zero lub jeden raz. Na przykład „a?ve?” odpowiada „ve” w słowie „lever”. | |
Odpowiada dowolnemu pojedynczemu znakowi, z wyjątkiem znaku nowej linii. | |
| Wyszukaj modèle i zapamiętaj dopasowanie. Odpowiedni podciąg można wyodrębnić z uzyskanej kolekcji Matches za pomocą elementu [0]...[n]. Aby znaleźć dopasowania zawierające znaki w nawiasach ( ), należy użyć znaków „\(" lub „\)”. |
| Odpowiada albo x, albo y. Na przykład „z|foot" correspond à "z" ou à "foot". "(z|f)oo” odpowiada „zoo” lub „foo”. |
| n to nieujemna liczba całkowita. Odpowiada dokładnie n pomnożonemu przez znak. Na przykład „o{2}” nie odpowiada literze „o” w słowie „Bob”, ale dwóm pierwszym literom „o” w słowie „fooooot”. |
| n to liczba całkowita nieujemna. Odpowiada co najmniej n-krotności danego znaku. Na przykład „o{2,}” nie odpowiada literze „o” w słowie „Bob”, ale wszystkim literom „o” w słowie „fooooot”. „o{1,}” jest równoważne „o+”, a „o{0,}” jest równoważne „o*”. |
| m i n to liczby całkowite nieujemne. Odpowiada co najmniej n i co najwyżej m wystąpieniom tego znaku. Na przykład „o{1,3}” odpowiada trzem pierwszym literom „o” w słowie „foooooot”, a „o{0,1}” jest równoważne „o?”. |
| Zestaw znaków. Odpowiada jednemu z podanych znaków. Na przykład „[abc]” odpowiada literze „a” w słowie „plat”. |
| Zbiór znaków ujemnych. Odpowiada każdemu znakowi, który nie został wymieniony. Na przykład „[^abc]” odpowiada literze „p” w słowie „plat”. |
| Zakres znaków. Odpowiada dowolnemu znakowi z podanego zakresu. Na przykład „[a-z]” odpowiada dowolnemu małej literze alfabetu od „a” do „z”. |
| Zakres znaków ujemny. Odpowiada dowolnemu znakowi, który nie występuje w podanym ciągu. Na przykład „[^m-z]” odpowiada dowolnemu znakowi, który nie występuje między „m” a „z”. |
Odpowiada granicy reprezentującej słowo, innymi słowy, pozycji między słowem a spacją. Na przykład „er\b” odpowiada „er” w słowie „lever”, ale nie odpowiada „er” w słowie „verbe”. | |
Odpowiada granicy, która nie reprezentuje słowa. „en*t\B” odpowiada „ent” w słowie „bien entendu”. | |
Odpowiada znakowi reprezentującemu cyfrę. Jest równoważne [0-9]. | |
Odpowiada znakowi, który nie jest cyfrą. Jest równoważny [^0-9]. | |
Odpowiada znakowi końca strony. | |
Odpowiada znakowi nowego wiersza. | |
Odpowiada znakowi powrotu karetki. | |
Odpowiada dowolnemu znakowi spacji, w tym spacji, tabulacji, znakowi końca strony itp. Odpowiada „[ \f\n\r\t\v]”. | |
Odpowiada dowolnemu znakowi spacji niebędącemu spacją. Odpowiada „[^ \f\n\r\t\v]”. | |
Odpowiada znakowi tabulacji. | |
Odpowiada znakowi pionowego tabulacji. | |
Odpowiada dowolnemu znakowi reprezentującemu słowo i zawierającemu podkreślenie. Odpowiada „[A-Za-z0-9_]”. | |
Odpowiada dowolnemu znakowi, który nie reprezentuje słowa. Odpowiada „[^A-Za-z0-9_]”. | |
| Odpowiada num, gdzie num jest dodatnią liczbą całkowitą. Odnosi się do zapisanych powiązań. Na przykład „(.)\1” odpowiada dwóm identycznym, następującym po sobie znakom. |
| Odpowiada n, gdzie n jest ośmiokrotną wartością escape. Ośmiokrotne wartości escape muszą składać się z 1, 2 lub 3 cyfr. Na przykład zarówno „\11”, jak i „\011” odpowiadają znakowi tabulacji. „\0011” jest równoważne „\001” i „1”. Oktalowe wartości escape nie mogą przekraczać 256. W przeciwnym razie w wyrażeniu brane pod uwagę będą tylko dwie pierwsze cyfry. Umożliwia używanie kodów ASCII w wyrażeniach regularnych. |
| Odpowiada n, gdzie n jest szesnastkową wartością escape. Wartości escape w systemie szesnastkowym muszą obowiązkowo składać się z dwóch cyfr. Na przykład „\x41” odpowiada literze „A”. „\x041” jest równoważne „\x04” i „1”. Umożliwia stosowanie kodów ASCII w wyrażeniach regularnych. |
Element w szablonie może występować w jednej lub wielu instancjach. Rozważmy kilka przykładów dotyczących symbolu \d, który reprezentuje jedną cyfrę:
szablon | znaczenie |
cyfra | |
0 lub 1 cyfra | |
0 lub więcej cyfr | |
1 lub więcej cyfr | |
2 cyfry | |
co najmniej 3 cyfry | |
od 5 do 7 cyfr |
Wyobraźmy sobie teraz model zdolny do opisania oczekiwanego formatu ciągu znaków:
poszukiwany ciąg znaków | model |
\d{2}/\d{2}/\d{2} | |
\d{2}:\d{2}:\d{2} | |
\d+ | |
\s* | |
\s*\d+\s* | |
\s*[+|-]?\s*\d+\s* | |
\s*\d+(.\d*)?\s* | |
\s*[+|]?\s*\d+(.\d*)?\s* | |
\bjuste\b | |
Można określić, w którym miejscu ciągu znaków ma być wyszukiwany wzorzec:
wzór | znaczenie |
szablon rozpoczyna ciąg | |
szablon kończy ciąg | |
szablon rozpoczyna i kończy ciąg | |
wzorzec jest wyszukiwany w całym ciągu, zaczynając od jego początku. |
szukany ciąg | wzorzec |
!$ | |
\.$ | |
^// | |
^\s*\w+\s*$ | |
^\s*\w+\s*\w+\s*$ | |
\bsecret\b |
Podzbiory wzorca można „wyodrębnić”. Dzięki temu nie tylko można sprawdzić, czy ciąg znaków odpowiada konkretnemu wzorcowi, ale także wyodrębnić z tego ciągu elementy odpowiadające podzbiorom wzorca, które zostały ujęte w nawiasy. Jeśli więc analizujemy ciąg zawierający datę dd/mm/rr i chcemy dodatkowo wyodrębnić elementy dd, mm, rr z tej daty, użyjemy wzorca (\d\d)/(\d\d)/(\d\d).
4.9.1. Sprawdzanie, czy ciąg znaków odpowiada podanemu wzorcowi
Obiekt typu Regex tworzy się w następujący sposób:
Konstruktor tworzy obiekt „wyrażenia regularnego” na podstawie wzorca przekazanego jako parametr (pattern). Po utworzeniu wzorca wyrażenia regularnego można go porównać z ciągami znaków za pomocą metody IsMatch:
IsMatch zwraca wartość true, jeśli ciąg znaków input odpowiada wzorcowi wyrażenia regularnego. Oto przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex1
Sub Main()
' wyrażenie regularne jako wzorzec
Dim modèle1 As String = "^\s*\d+\s*$"
Dim regex1 As New Regex(modèle1)
' porównanie egzemplarza z wzorcem
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
' wyświetla
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
oraz wyniki wykonania:
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. Znajdź wszystkie elementy ciągu znaków pasujące do wzorca
Metoda Matches
zwraca zbiór elementów ciągu znaków input pasujących do wzorca, jak pokazano w poniższym przykładzie:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex2
Sub Main()
' wiele wystąpień wzorca w egzemplarzu
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
'wyświetla
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
Klasa MatchCollection posiada właściwość Count, która określa liczbę elementów w kolekcji. Jeśli résultats jest obiektem MatchCollection, to résultats(i) jest elementem i tej kolekcji i ma typ Match. W naszym przykładzie résultats to zbiór elementów ciągu exemplaire3 odpowiadających modelowi modèle2, a résultats(i) jest jednym z tych elementów. Klasa Match posiada dwie właściwości, które nas tutaj interesują:
- Value: wartość obiektu Match, czyli elementu odpowiadającego modelowi
- Index: pozycja, na której element został znaleziony w przeszukiwanym ciągu
Wyniki wykonania poprzedniego programu:
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. Pobieranie części wzorca
Podzbiory wzorca można „wyodrębnić”. Dzięki temu nie tylko można sprawdzić, czy ciąg znaków odpowiada konkretnemu wzorcowi, ale także wyodrębnić z tego ciągu elementy odpowiadające podzbiorom wzorca, które zostały ujęte w nawiasy. Jeśli więc analizujemy ciąg znaków zawierający datę dd/mm/rr i chcemy dodatkowo wyodrębnić elementy dd, mm, rr z tej daty, użyjemy wzorca (\d\d)/(\d\d)/(\d\d). Rozważmy następujący przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Module regex2
Sub Main()
' pobieranie elementów z szablonu
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"
' weryfikacja szablonu
Dim résultat As Match = regex3.Match(exemplaire4)
If résultat.Success Then
' egzemplarz jest zgodny z szablonem
affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
' wyświetlanie grup
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
' egzemplarz nie odpowiada szablonowi
affiche(("L'exemplaire[" + exemplaire4 + " ne correspond pas au modèle [" + modèle3 + "]"))
End If
End Sub
'wyświetla
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
Wykonanie tego programu daje następujące wyniki:
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
Nowość znajduje się w następującym fragmencie kodu:
' weryfikacja szablonu
Dim résultat As Match = regex3.Match(exemplaire4)
If résultat.Success Then
' egzemplarz odpowiada szablonowi
affiche(("L'exemplaire [" + exemplaire4 + "] correspond au modèle [" + modèle3 + "]"))
' wyświetlane są grupy
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
Ciąg znaków exemplaire4 jest porównywany z wzorcem regex3 za pomocą metody Match. Metoda ta zwraca obiekt Match, który został już przedstawiony. Wykorzystujemy tutaj dwie nowe właściwości tej klasy:
- Success: wskazuje, czy znaleziono dopasowanie
- Groups: zbiór, w którym
- Groups[0] odpowiada części ciągu znaków odpowiadającej wzorcowi
- Groups[i] (i>=1) odpowiada grupie nawiasów o numerze i
Jeśli wynik jest typu Match, résultats.Groups jest typu GroupCollection, a résultats.Groups[i] jest typu Group. Klasa Group posiada dwie właściwości, z których tutaj korzystamy:
- Value: wartość obiektu Group, której element odpowiada zawartości nawiasu
- Index: pozycja, w której element został znaleziony w analizowanym ciągu
4.9.4. Program do nauki
Znalezienie wyrażenia regularnego, które pozwoli nam sprawdzić, czy dany ciąg znaków odpowiada określonemu wzorcowi, bywa prawdziwym wyzwaniem. Poniższy program pozwala poćwiczyć tę umiejętność. Wymaga on podania wzorca i ciągu znaków, a następnie wskazuje, czy ciąg ten odpowiada wzorcowi, czy nie.
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.visualbasic
Module regex4
Sub Main()
' wyrażenie regularne wzorca
Dim modèle, chaine As String
Dim regex As Regex = Nothing
Dim résultats As MatchCollection
' użytkownik jest proszony o podanie wzorców i egzemplarzy, które mają zostać porównane z tym egzemplarzem
Dim terminé1 As Boolean = False
Do While Not terminé1
Dim erreur As Boolean = True
Do While Not terminé1 And erreur
' pyta się o wzorzec
Console.Out.Write("Tapez le modèle à tester ou fin pour arrêter :")
modèle = Console.In.ReadLine()
' koniec?
If modèle.Trim().ToLower() = "fin" Then
terminé1 = True
Else
' tworzy się wyrażenie regularne
Try
regex = New Regex(modèle)
erreur = False
Catch ex As Exception
Console.Error.WriteLine(("Erreur : " + ex.Message))
End Try
End If
Loop
' gotowe?
If terminé1 Then Exit Sub
' pyta się użytkownika o egzemplarze, które mają zostać porównane z wzorcem
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()
' zakończone?
If chaine.Trim().ToLower() = "fin" Then
terminé2 = True
Else
' przeprowadzamy porównanie
résultats = regex.Matches(chaine)
' powodzenie?
If résultats.Count = 0 Then
Console.Out.WriteLine("Je n'ai pas trouvé de correspondances")
Else
' wyświetlane są elementy odpowiadające wzorcowi
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))
' podelementy
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
'wyświetla
Sub affiche(ByVal msg As String)
Console.Out.WriteLine(msg)
End Sub
End Module
Oto przykładowe wyniki działania:
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. Metoda Split
Metodę tę poznaliśmy już w klasie String:
Ciąg znaków jest traktowany jako sekwencja pól rozdzielonych znakami zawartymi w tablicy [separator]. Wynikiem jest tablica tych pól.
Separatorem pól w ciągu znaków jest tutaj jeden ze znaków z tablicy separator. Metoda Split z klasy Regex pozwala nam określić separator na podstawie wzorca:
Ciąg znaków [input] jest rozkładany na pola, które są oddzielone separatorem odpowiadającym wzorcowi bieżącego obiektu Regex. Załóżmy na przykład, że w pliku tekstowym mamy wiersze w postaci pole1, pole2, …, polen. Pola są oddzielone przecinkiem, ale przed nim lub po nim mogą występować spacje. Metoda Split klasy string nie jest w tym przypadku odpowiednia. Rozwiązaniem jest metoda RegEx. Jeśli ligne jest odczytanym wierszem, pola można uzyskać za pomocą
jak pokazuje poniższy przykład:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Text.RegularExpressions
Module regex5
Sub Main()
' wiersz
Dim ligne As String = "abc , def , ghi"
' szablon
Dim modèle As New Regex("\s*,\s*")
' podział wiersza na pola
Dim champs As String() = modèle.Split(ligne)
' wyświetlanie
Dim i As Integer
For i = 0 To champs.Length - 1
Console.Out.WriteLine(("champs[" & i & "]=[" & champs(i) & "]"))
Next i
End Sub
End Module
Wyniki wykonania:
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. Klasy BinaryReader i BinaryWriter
Klasy BinaryReader i BinaryWriter służą do odczytu i zapisu plików binarnych. Rozważmy następującą aplikację. Chcemy napisać program, który wywoływałby się w następujący sposób:
// składnia pg tekst bin
// odczyt pliku tekstowego (tekst) i zapisanie jego zawartości w
// plik binarny
// plik tekstowy zawiera wiersze w postaci: imię : wiek
// które zostaną zapisane w strukturze typu string, int
Plik tekstowy zawiera następującą treść:
Program wygląda następująco:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
' BinaryWriter()
Module bw1
' składnia pg tekst bin
' odczytuje się plik tekstowy (tekst) i zapisuje jego zawartość w
' plik binarny
' plik tekstowy zawiera wiersze w postaci: imię : wiek
' które zostaną zapisane w strukturze typu string, int
Sub Main(ByVal arguments() As String)
' potrzebne są 2 argumenty
Dim nbArgs As Integer = arguments.Length
If nbArgs <> 2 Then
Console.Error.WriteLine("syntaxe : pg texte binaire")
Environment.Exit(1)
End If
' otwarcie pliku tekstowego do odczytu
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
' otwarcie pliku binarnego do zapisu
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
' odczyt pliku tekstowego – zapis pliku binarnego
' wiersz pliku tekstowego
Dim ligne As String
' separator pól w wierszu
Dim séparateur As New Regex("\s*:\s*")
' wzór wieku
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
' pusty wiersz?
If ligne.Trim() = "" Then
traitementFini = True
End If
' kolejny wiersz
If Not traitementFini Then
numLigne += 1
' wiersz: imię i nazwisko: wiek
champs = séparateur.Split(ligne)
' potrzebujemy 2 pól
If champs.Length <> 2 Then
Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un nombre de champs incorrect"))
' następny wiersz
traitementFini = True
End If
End If
If Not traitementFini Then
' drugie pole musi być liczbą całkowitą >=0
If Not modAge.IsMatch(champs(1)) Then
Console.Error.WriteLine(("La ligne n° " & numLigne & " du fichier " & arguments(0) & " a un âge incorrect"))
' kolejny wiersz
traitementFini = True
End If
' zapisujemy dane do pliku binarnego
output.Write(champs(0))
output.Write(Integer.Parse(champs(1)))
End If
'następny wiersz
ligne = input.ReadLine()
End While
' zamknięcie plików
input.Close()
output.Close()
End Sub
End Module
Przyjrzyjmy się operacjom dotyczącym klasy BinaryWriter:
- obiekt BinaryWriter jest otwierany przez operację
output = New BinaryWriter(New FileStream(arguments(1), FileMode.Create, FileAccess.Write))
Argumentem konstruktora musi być strumień (Stream). W tym przypadku jest to strumień utworzony na podstawie pliku (FileStream), dla którego podajemy:
- (ciąg dalszy)
- nazwę
- operację do wykonania, w tym przypadku FileMode.Create w celu utworzenia pliku
- typ dostępu, w tym przypadku FileAccess.Write dla dostępu z prawem zapisu do pliku
- operację zapisu
' zapis danych do pliku binarnego
output.Write(champs(0))
output.Write(Integer.Parse(champs(1)))
Klasa BinaryWriter posiada różne nadpisane metody Write służące do zapisywania różnych typów danych prostych
- operacja zamknięcia strumienia
Wyniki poprzedniego wykonania zostaną nam podane przez poniższy program. Program ten również przyjmuje dwa argumenty:
' składnia pg bin tekst
' odczyt pliku binarnego bin i zapisanie jego zawartości w pliku tekstowym (tekst)
' plik binarny ma strukturę typu string, int
' plik tekstowy zawiera wiersze w postaci: imię : wiek
Wykonujemy więc operację odwrotną. Odczytujemy plik binarny, aby utworzyć plik tekstowy. Jeśli wygenerowany plik tekstowy będzie identyczny z plikiem źródłowym, będziemy mieli pewność, że konwersja tekst → binarny → tekst przebiegła pomyślnie. Kod wygląda następująco:
' opcje
Option Strict On
Option Explicit On
' przestrzenie nazw
Imports System
Imports System.Text.RegularExpressions
Imports System.IO
Module br1
' składnia pg bin tekst
' odczytuje się plik binarny bin i zapisuje jego zawartość w pliku tekstowym (tekst)
' plik binarny ma strukturę typu string, int
' plik tekstowy zawiera wiersze w postaci: imię : wiek
Sub Main(ByVal arguments() As String)
' potrzebne są 2 argumenty
Dim nbArgs As Integer = arguments.Length
If nbArgs <> 2 Then
Console.Error.WriteLine("syntaxe : pg binaire texte")
Environment.Exit(1)
End If
' otwarcie pliku binarnego do odczytu
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
' otwarcie pliku tekstowego do zapisu
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
' odczyt pliku binarnego – zapis pliku tekstowego
Dim nom As String ' nom d'une personne
Dim age As Integer ' son âge
' pętla przetwarzania pliku binarnego
While True
' odczyt nazwy
Try
nom = dataIn.ReadString()
Catch
' koniec pliku
Exit Sub
End Try
' odczyt wieku
Try
age = dataIn.ReadInt32()
Catch
Console.Error.WriteLine("Le fichier " & arguments(0) + " ne semble pas avoir un format correct")
Exit Sub
End Try
' zapis do pliku tekstowego
dataOut.WriteLine(nom & ":" & age)
System.Console.WriteLine(nom & ":" & age)
End While
' zamykamy wszystko
dataIn.Close()
dataOut.Close()
End Sub
End Module
Przyjrzyjmy się operacjom dotyczącym klasy BinaryReader:
- obiekt BinaryReader jest otwierany przez operację
dataIn = New BinaryReader(New FileStream(arguments(0), FileMode.Open, FileAccess.Read))
Argumentem konstruktora musi być strumień (Stream). W tym przypadku jest to strumień utworzony na podstawie pliku (FileStream), dla którego podajemy:
- (ciąg dalszy)
- nazwę
- operację do wykonania, w tym przypadku FileMode.Open w celu otwarcia istniejącego pliku
- typ dostępu, w tym przypadku FileAccess.Read dla dostępu do pliku w trybie odczytu
- operację odczytu
Klasa BinaryReader posiada różne metody ReadXX do odczytu różnych typów danych prostych
- operacja zamknięcia strumienia
Jeśli uruchomimy oba programy po kolei, przekształcając personnes.txt w personnes.bin, a następnie personnes.bin w personnes.txt2, otrzymamy:

