5. Yaygın olarak kullanılan .NET sınıfları
Burada, .NET platformunda sıkça kullanılan bazı sınıfları tanıtıyoruz. Öncelikle, mevcut olan birkaç yüz sınıf hakkında nasıl bilgi edinebileceğinizi göstereceğiz. Bu yardım, deneyimli C# geliştiricileri için bile vazgeçilmezdir. Bir yardım belgesinin kalitesi (kolay erişim, anlaşılır düzen, bilgilerin uygunluğu vb.), bir geliştirme ortamının başarısını veya başarısızlığını belirleyebilir.
5.1. .NET sınıfları hakkında yardım arama
Burada, Visual Studio.NET ile yardım bulmak için bazı ipuçları veriyoruz
5.1.1. Yardım/İçindekiler
![]() |
- [1]'te, menüden Help/Contents seçeneğini seçin.
- [2]'te, Visual C# Express Edition seçeneğini seçin
- [3]'te, C# yardım ağacı
- [4]'te, başka bir yararlı seçenek de .NET Framework'tür; bu, .NET framework'ündeki tüm sınıflara erişim sağlar.
C# yardımındaki bölüm başlıklarına bir göz atalım:
![]() |
- [1]: C#'a genel bakış
- [2]: C#'ın belirli konularına ilişkin bir dizi örnek
- [3]: Bir C# kursu – bu belgeyi avantajlı bir şekilde ikame edebilir…
![]() |
- [4]: C#'ın ayrıntılarına dalmak için
- [5]: C++ veya Java geliştiricileri için yararlıdır. Bazı tuzaklardan kaçınmanıza yardımcı olur.
- [6]: Örnekler arıyorsanız, buradan başlayabilirsiniz.
![]() |
- [7]: Grafik kullanıcı arayüzleri oluşturmak için bilmeniz gerekenler
- [8]: IDE Visual Studio Express'i daha iyi kullanmak için
![]() |
- [9]: SQL Server Express 2005, ücretsiz olarak dağıtılan kaliteli bir SGBD yazılımıdır. Bu derste onu kullanacağız.
C# yardımı, geliştiricinin ihtiyaç duyduğu şeylerin sadece bir kısmıdır. Diğer kısmı ise, işini kolaylaştıracak .NET çerçevesindeki yüzlerce sınıfla ilgili yardımdır.
![]() |
- [1]: .NET çerçeve yardımını seçin
- [2]: Yardım, .NET Framework dalında bulunur SDK
- [3]: .NET Framework Sınıf Kütüphanesi dalı, ait oldukları ad alanına göre tüm .NET sınıflarını gösterir
- [4]: Önceki bölümlerdeki örneklerde en sık kullanılan System ad alanı
![]() |
- [5]: System ad alanında yer alan bir örnek; burada DateTime yapısı
![]() |
- [6]: DateTime yapısı hakkında yardım
5.1.2. Yardım/Dizin/Arama
MSDN tarafından sağlanan yardım çok kapsamlıdır ve nereden başlayacağınızı bilemeyebilirsiniz. Bu durumda yardım dizinini kullanabilirsiniz:
![]() |
- [1]'te, yardım penceresi henüz açık değilse [Help/Index] seçeneğini kullanın; aksi takdirde mevcut bir yardım penceresinde [2]'i kullanın.
- [3] komutuyla, aramanın yapılacağı alanı belirtin
- [4]'te, ne aradığınızı belirtin; burada bir sınıf
- [5]'te, yanıt
Yardım aramanın bir başka yolu da yardım bölümündeki arama işlevini kullanmaktır:
![]() |
- [1]'te, yardım penceresi henüz açık değilse [Help/Search] seçeneğini kullanın; aksi takdirde mevcut bir yardım penceresinde [2]'i kullanın.
- [3]'e, arananı belirtin
- [4]'te, arama alanlarını filtreleyin
![]() |
- [5]'te, aranan metnin bulunduğu farklı başlıklar halinde yanıt.
5.2. Karakter dizileri
5.2.1. System.String sınıfı
![]() | ![]() | ![]() |
System.String sınıfı, basit string türüyle aynıdır. Bu sınıfın birçok özelliği ve yöntemi vardır. İşte bunlardan bazıları:
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
Önemli bir noktaya dikkat çekmek gerekir: Bir yöntem bir karakter dizisi döndürdüğünde, bu dizisi, yöntemin uygulandığı diziden farklı bir dizidir. Dolayısıyla, S1.Trim() işlevi S2 dizesini döndürür; S1 ve S2 ise birbirinden farklı iki dizedir.
Bir C dizesi, bir karakter dizisi olarak düşünülebilir. Dolayısıyla
- C[i], C dizisindeki i karakteridir
- C.Length, C dizisinin karakter sayısıdır
Şu örneği ele alalım:
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
string uneChaine = "l'oiseau vole au-dessus des nuages";
affiche("uneChaine=" + uneChaine);
affiche("uneChaine.Length=" + uneChaine.Length);
affiche("chaine[10]=" + uneChaine[10]);
affiche("uneChaine.IndexOf(\"vole\")=" + uneChaine.IndexOf("vole"));
affiche("uneChaine.IndexOf(\"x\")=" + uneChaine.IndexOf("x"));
affiche("uneChaine.LastIndexOf('a')=" + uneChaine.LastIndexOf('a'));
affiche("uneChaine.LastIndexOf('x')=" + uneChaine.LastIndexOf('x'));
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', 'A'));
string[] champs = uneChaine.Split(null);
for (int i = 0; i < champs.Length; i++) {
affiche("champs[" + i + "]=[" + champs[i] + "]");
}//for
affiche("Join(\":\",champs)=" + System.String.Join(":", champs));
affiche("(\" abc \").Trim()=[" + " abc ".Trim() + "]");
}//Ana
public static void affiche(string msg) {
// mesajı görüntüler
Console.WriteLine(msg);
}//görüntüler
}//sınıf
}//ad alanı
Çalıştırıldığında şu sonuçlar elde edilir:
Başka bir örnek ele alalım:
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// analiz edilecek satır
string ligne = "un:deux::trois:";
// alan ayırıcıları
char[] séparateurs = new char[] { ':' };
// bölme
string[] champs = ligne.Split(séparateurs);
for (int i = 0; i < champs.Length; i++) {
Console.WriteLine("Champs[" + i + "]=" + champs[i]);
}
// birleştirme
Console.WriteLine("join=[" + System.String.Join(":", champs) + "]");
}
}
}
ve çalıştırma sonuçları:
String sınıfının Split yöntemi, bir karakter dizisinin öğelerini bir diziye yerleştirmeye olanak tanır. Burada kullanılan Split yönteminin tanımı şöyledir:
public string[] Split(char[] separator);
karakter tablosu. Bu karakterler, karakter dizisindeki alanları ayırmak için kullanılan karakterleri temsil eder. Dolayısıyla, karakter dizisi "champ1, champ2, champ3"" ise, separator=new char[] {','} kullanabiliriz. Ayırıcı bir dizi boşluktan oluşuyorsa, separator=null kullanılır. | |
dizinin her bir elemanı, dizenin bir alanı olan karakter dizilerinden oluşan bir dizi. |
Join yöntemi, String sınıfının statik bir yöntemidir:
public static string Join(string separator, string[] value);
dize dizisi | |
alan ayırıcısı olarak kullanılacak bir karakter dizesi | |
value dizisindeki öğelerin, separator dizisiyle ayrılmış olarak birleştirilmesiyle oluşturulan bir karakter dizisi. |
5.2.2. System.Text.StringBuilder sınıfı
![]() | ![]() | ![]() |
Daha önce, S1 karakter dizisine uygulanan String sınıfının yöntemlerinin, başka bir S2 karakter dizisi döndürdüğünü belirtmiştik. System.Text.StringBuilder sınıfı, S1 dizesini, S2 dizesi oluşturmaya gerek kalmadan işlememize olanak tanır. Bu, ömrü çok kısa olan dizelerin çoğalmasını önleyerek performansı artırır.
Sınıf, çeşitli oluşturucuları destekler:
| |
|
Bir StringBuilder nesnesi, altta yatan dizgiyi depolamak için capacité karakterlik bloklarla çalışır. Varsayılan olarak capacité değeri 16'dır. Yukarıdaki 3. oluşturucu, blokların kapasitesini belirlemeye olanak tanır. Bir S dizisini depolamak için gereken capacité karakter bloklarının sayısı, StringBuilder sınıfı tarafından otomatik olarak ayarlanır. Bir StringBuilder nesnesindeki maksimum karakter sayısını belirlemek için oluşturucular mevcuttur. Varsayılan olarak, bu maksimum kapasite 2.147.483.647'dir.
Aşağıda, capacité kavramını açıklayan bir örnek verilmiştir:
using System.Text;
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// str
StringBuilder str = new StringBuilder("test");
Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity);
for (int i = 0; i < 10; i++) {
str.Append("test");
Console.WriteLine("taille={0}, capacité={1}", str.Length, str.Capacity);
}
// str2
StringBuilder str2 = new StringBuilder("test",10);
Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity);
for (int i = 0; i < 10; i++) {
str2.Append("test");
Console.WriteLine("taille={0}, capacité={1}", str2.Length, str2.Capacity);
}
}
}
}
- 7. satır: 16 karakterlik blok boyutuna sahip bir StringBuilder nesnesinin oluşturulması
- 8. satır: str.Length, str dizesinin mevcut karakter sayısıdır. str.Capacity, yeni bir blok tahsis edilmeden önce mevcut str dizesinin depolayabileceği karakter sayısıdır.
- 10. satır: str.Append(String S), String türündeki S dizesini, StringBuilder türündeki str dizesine birleştirmeye olanak tanır.
- 14. satır: 10 karakterlik blok kapasitesine sahip bir StringBuilder nesnesi oluşturulur
Çalıştırma sonucu:
Bu sonuçlar, sınıfın kapasitesi yetersiz olduğunda yeni bloklar tahsis etmek için kendine özgü bir algoritma izlediğini göstermektedir:
- 4-5. satırlar: kapasitenin 16 karakter artırılması
- 8-9. satırlar: 16 karakter yeterli olurken kapasite 32 karakter artırıldı.
İşte sınıfın bazı yöntemleri:
| |
| |
| |
| |
|
İşte bir örnek:
using System.Text;
using System;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// str3
StringBuilder str3 = new StringBuilder("test");
Console.WriteLine(str3.Append("abCD").Insert(2, "xyZT").Remove(0, 2).Replace("xy", "XY"));
}
}
}
ve sonuçları:
5.3. Diziler
Tablolar, Array sınıfından türetilir:
![]() | ![]() | ![]() |
Array sınıfı, bir diziyi sıralamak, bir dizide bir elemanı aramak, bir dizinin boyutunu değiştirmek vb. için çeşitli yöntemlere sahiptir. Bu sınıfın bazı özelliklerini ve yöntemlerini tanıtıyoruz. Bunların neredeyse tamamı, farklı varyantlarda mevcut olacak şekilde aşırı yüklenmiştir (c.a.d). Her dizi bu özellikleri miras alır.
Özellikler
Yöntemler
Aşağıdaki program, Array sınıfındaki bazı yöntemlerin kullanımını göstermektedir:
using System;
namespace Chap3 {
class Program {
// arama türü
enum TypeRecherche { linéaire, dichotomique };
// ana yöntem
static void Main(string[] args) {
// klavyeyle girilen tablo öğelerinin okunması
double[] éléments;
Saisie(out éléments);
// sıralanmamış tablonun görüntülenmesi
Affiche("Tableau non trié", éléments);
// Sıralanmamış tabloda doğrusal arama
Recherche(éléments, TypeRecherche.linéaire);
// dizinin sıralanması
Array.Sort(éléments);
// sıralanmış tablonun görüntülenmesi
Affiche("Tableau trié", éléments);
// Sıralanmış tabloda ikili arama
Recherche(éléments, TypeRecherche.dichotomique);
}
// elemanlar tablosuna değerlerin girilmesi
// elemanlar: yöntemle oluşturulan tabloya referans
static void Saisie(out double[] éléments) {
bool terminé = false;
string réponse;
bool erreur;
double élément = 0;
int i = 0;
// Başlangıçta tablo mevcut değildir
éléments = null;
// dizinin elemanlarını girme döngüsü
while (!terminé) {
// soru
Console.Write("Elément (réel) " + i + " du tableau (rien pour terminer) : ");
// cevabın okunması
réponse = Console.ReadLine().Trim();
// dize boşsa girişin sonlandırılması
if (réponse.Equals(""))
break;
// girişin doğrulanması
try {
élément = Double.Parse(réponse);
erreur = false;
} catch {
Console.Error.WriteLine("Saisie incorrecte, recommencez");
erreur = true;
}//try-catch
// hata yoksa
if (!erreur) {
// diziye bir öğe daha eklenir
i += 1;
// yeni elemanı eklemek için dizinin boyutunu değiştirme
Array.Resize(ref éléments, i);
// yeni elemanın eklenmesi
éléments[i - 1] = élément;
}
}//while
}
// bir dizideki elemanları görüntülemek için genel yöntem
static void Affiche<T>(string texte, T[] éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
// tabloda bir öğeyi arama
// elemanlar: gerçek sayı tablosu
// TypeRecherche: ikili veya doğrusal
static void Recherche(double[] éléments, TypeRecherche type) {
// Arama
bool terminé = false;
string réponse = null;
double élément = 0;
bool erreur = false;
int i = 0;
while (!terminé) {
// soru
Console.WriteLine("Elément cherché (rien pour arrêter) : ");
// cevabı okuma-doğrulama
réponse = Console.ReadLine().Trim();
// bitti mi?
if (réponse.Equals(""))
break;
// doğrulama
try {
élément = Double.Parse(réponse);
erreur = false;
} catch {
Console.WriteLine("Erreur, recommencez...");
erreur = true;
}//try-catch
// hata yoksa
if (!erreur) {
// dizide eleman aranıyor
if (type == TypeRecherche.dichotomique)
// ikili arama
i = Array.BinarySearch(éléments, élément);
else
// doğrusal arama
i = Array.IndexOf(éléments, élément);
// Cevabın görüntülenmesi
if (i >= 0)
Console.WriteLine("Trouvé en position " + i);
else
Console.WriteLine("Pas dans le tableau");
}//if
}//while
}
}
}
- 27-62. satırlar: Saisie yöntemi, klavyeden girilen éléments dizisinin elemanlarını alır. Dizinin boyutunu önceden belirleyemediğimiz için (nihai boyutunu bilmiyoruz), her yeni eleman eklendiğinde dizinin boyutunu yeniden ayarlamak zorunda kalırız (satır 57). Daha verimli bir algoritma, tabloya N'lik öğe grupları halinde yer ayırmak olurdu. Ancak bir tablo, yeniden boyutlandırılmak üzere tasarlanmamıştır. Bu durum, bir liste (ArrayList, List<T>) kullanılarak daha iyi ele alınabilir.
- 75-113. satırlar: Recherche yöntemi, éléments dizisinde klavyeden girilen bir öğeyi aramaya olanak tanır. Arama yöntemi, dizinin sıralı olup olmamasına göre farklılık gösterir. Sıralı olmayan bir dizi için, 106. satırdaki IndexOf yöntemi kullanılarak doğrusal arama yapılır. Sıralı bir dizi için ise, 103. satırdaki BinarySearch yöntemi kullanılarak ikili arama yapılır.
- 18. satır: éléments tablosu sıralanır. Burada, tek bir parametreye sahip olan Sort yönteminin bir varyantı kullanılır: sıralanacak tablo. Dizinin elemanlarını karşılaştırmak için kullanılan sıralama ilişkisi, bu elemanların örtük sıralamasıdır. Burada elemanlar sayısaldır. Sayıların doğal sıralaması kullanılır.
Ekran sonuçları şöyledir:
5.4. Genel koleksiyonlar
Tablonun yanı sıra, öğe koleksiyonlarını depolamak için çeşitli sınıflar mevcuttur. System.Collections.Generic ad alanında genel sürümler, System.Collections ad alanında ise genel olmayan sürümler bulunmaktadır. Sıkça kullanılan iki genel koleksiyonu tanıtacağız: liste ve sözlük.
Genel koleksiyonların listesi şöyledir:

5.4.1. List<T> jenerik sınıfı
System.Collections.Generic.List<T> sınıfı, programın çalışması sırasında boyutu değişen T türündeki nesnelerden oluşan koleksiyonları uygulamaya olanak tanır. List<T> türündeki bir nesne, neredeyse bir dizi gibi işlenir. Dolayısıyla, l listesinin i elemanı l[i] olarak gösterilir.
Ayrıca, herhangi bir nesneye ait referansları depolayabilen, jenerik olmayan bir liste türü de mevcuttur: ArrayList. ArrayList, işlevsel olarak List<Object>. ile eşdeğerdir. Bir ArrayList nesnesi şu şekildedir:
![]() |
Yukarıda, listenin 0, 1 ve i numaralı öğeleri farklı türlerdeki nesnelere işaret etmektedir. Bir nesneye ArrayList listesine referans eklenmeden önce nesnenin oluşturulması gerekir. Bir ArrayList nesnesi nesne referanslarını depolasa da, bu nesneye sayılar da depolanabilir. Bu, Boxing adlı bir mekanizma aracılığıyla gerçekleştirilir: sayı, Object türünde bir O nesnesine kapsüllenir ve listeye O nesnesinin referansı kaydedilir. Bu, geliştirici için şeffaf bir mekanizmadır. Böylece şu şekilde yazılabilir:
Bu, aşağıdaki sonucu verecektir:
![]() |
Yukarıda, 4 sayısı bir O nesnesine kapsüllenmiştir ve O referansı listede saklanmıştır. Bunu geri almak için şu şekilde yazabiliriz:
int i = (int)liste[0];
Object -> int işlemi, Unboxing olarak adlandırılır. Bir liste tamamen int türlerinden oluşuyorsa, onu List<int> olarak tanımlamak performansı artırır. Çünkü bu durumda int türündeki sayılar, listenin dışındaki Object türlerinde değil, listenin içinde depolanır. Böylece Boxing / Unboxing işlemleri artık gerçekleşmez.
List<T> veya T bir sınıf ise, liste yine T türündeki nesnelerin referanslarını depolar:
![]() |
İşte genel listelerin bazı özellikleri ve yöntemleri:
Özellikler
Yöntemler
Daha önce ele aldığımız Array türündeki nesneyle ilgili örneği tekrar ele alalım ve şimdi bunu List<T>. türündeki bir nesneyle işleyelim. Liste, tabloya benzer bir nesne olduğu için kodda çok az değişiklik oluyor. Yalnızca dikkate değer değişiklikleri sunuyoruz:
using System;
using System.Collections.Generic;
namespace Chap3 {
class Program {
// arama türü
enum TypeRecherche { linéaire, dichotomique };
// ana yöntem
static void Main(string[] args) {
// klavyeden girilen liste öğelerini okuma
List<double> éléments;
Saisie(out éléments);
// öğe sayısı
Console.WriteLine("La liste a {0} éléments et une capacité de {1} éléments", éléments.Count, éléments.Capacity);
// sıralanmamış listenin görüntülenmesi
Affiche("Liste non triée", éléments);
// Sıralanmamış listede doğrusal arama
Recherche(éléments, TypeRecherche.linéaire);
// Listenin sıralanması
éléments.Sort();
// sıralanmış liste görüntüleme
Affiche("Liste triée", éléments);
// Sıralanmış listede ikili arama
Recherche(éléments, TypeRecherche.dichotomique);
}
// Liste öğelerinin değerlerinin girilmesi
// elemanlar: yöntem tarafından oluşturulan listeye referans
static void Saisie(out List<double> éléments) {
...
// Başlangıçta liste boştur
éléments = new List<double>();
// Liste öğelerini girme döngüsü
while (!terminé) {
...
// hata yoksa
if (!erreur) {
// listeye bir öğe daha eklenir
éléments.Add(élément);
}
}//while
}
// sayılabilir bir nesnenin öğelerini görüntülemek için genel yöntem
static void Affiche<T>(string texte, IEnumerable<T> éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
// listede bir öğeyi arama
// elemanlar: gerçek sayı listesi
// TypeRecherche: ikili veya doğrusal
static void Recherche(List<double> éléments, TypeRecherche type) {
...
while (!terminé) {
...
// hata yoksa
if (!erreur) {
// listede eleman aranıyor
if (type == TypeRecherche.dichotomique)
// ikili arama
i = éléments.BinarySearch(élément);
else
// doğrusal arama
i = éléments.IndexOf(élément);
// Cevabın görüntülenmesi
...
}//if
}//while
}
}
}
- 46-51. satırlar: Affiche<T> genel yöntemi iki parametre kabul eder:
- 1. parametre yazılacak metindir
- 2. parametre, IEnumerable<T> jenerik arayüzünü uygulayan bir nesnedir:
- satırdaki foreach( T öğe in öğeler) yapısı, IEnumerable arayüzünü uygulayan tüm éléments nesneleri için geçerlidir. Diziler (Array) ve listeler (List<T>), IEnumerable<T> arayüzünü uygular. Bu nedenle Affiche yöntemi, hem tabloları hem de listeleri görüntülemek için uygundur.
Programın çalıştırma sonuçları, Array sınıfının kullanıldığı örnektekiyle aynıdır.
5.4.2. Dictionary<TKey,TValue> sınıfı
System.Collections.Generic.Dictionary<TKey,TValue> sınıfı, bir sözlükün uygulanmasına olanak tanır. Bir sözlük, iki sütunlu bir tablo olarak düşünülebilir:
anahtar | değer |
anahtar1 | değer1 |
anahtar2 | değer2 |
.. | ... |
Dictionary<TKey,TValue> sınıfında anahtarlar Tkey türündedir, değerler ise TValue türündedir. Anahtarlar benzersizdir; c.a.d. Yani iki anahtarın aynı olması mümkün değildir. TKey ve TValue türleri sınıfları ifade ediyorsa, böyle bir sözlük şu şekilde görünebilir:
![]() |
D sözlüğündeki C anahtarına atanan değer, D[C] notasyonu ile elde edilir. Bu değer hem okunabilir hem de yazılabilir. Dolayısıyla şöyle yazabiliriz:
c anahtarı D sözlüğünde mevcut değilse, D[c] notasyonu bir istisna oluşturur.
Dictionary<TKey,TValue> sınıfının başlıca yöntemleri ve özellikleri şunlardır:
Oluşturucular
Özellikler
Yöntemler
Aşağıdaki örnek programı ele alalım:
using System;
using System.Collections.Generic;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// <string,int> türünde bir sözlük oluşturma
string[] liste = { "jean:20", "paul:18", "mélanie:10", "violette:15" };
string[] champs = null;
char[] séparateurs = new char[] { ':' };
Dictionary<string,int> dico = new Dictionary<string,int>();
for (int i = 0; i <liste.Length; i++) {
champs = liste[i].Split(séparateurs);
dico[champs[0]]= int.Parse(champs[1]);
}//for
// sözlükteki öğe sayısı
Console.WriteLine("Le dictionnaire a " + dico.Count + " éléments");
// anahtarların listesi
Affiche("[Liste des clés]",dico.Keys);
// değerlerin listesi
Affiche("[Liste des valeurs]", dico.Values);
// anahtar ve değerlerin listesi
Console.WriteLine("[Liste des clés & valeurs]");
foreach (string clé in dico.Keys) {
Console.WriteLine("clé=" + clé + " valeur=" + dico[clé]);
}
// "paul" anahtarı siliniyor
Console.WriteLine("[Suppression d'une clé]");
dico.Remove("paul");
// anahtar ve değer listesi
Console.WriteLine("[Liste des clés & valeurs]");
foreach (string clé in dico.Keys) {
Console.WriteLine("clé=" + clé + " valeur=" + dico[clé]);
}
// sözlükte arama
String nomCherché = null;
Console.Write("Nom recherché (rien pour arrêter) : ");
nomCherché = Console.ReadLine().Trim();
int value;
while (!nomCherché.Equals("")) {
dico.TryGetValue(nomCherché, out value);
if (value!=0) {
Console.WriteLine(nomCherché + "," + value);
} else {
Console.WriteLine("Nom " + nomCherché + " inconnu");
}
// sonraki arama
Console.Out.Write("Nom recherché (rien pour arrêter) : ");
nomCherché = Console.ReadLine().Trim();
}//while
}
// sayılabilir bir türün öğelerini görüntülemek için genel yöntem
static void Affiche<T>(string texte, IEnumerable<T> éléments) {
Console.WriteLine(texte.PadRight(50, '-'));
foreach (T élément in éléments) {
Console.WriteLine(élément);
}
}
}
}
- 8. satır: <string,int> sözlüğünü başlatmak için kullanılacak bir string dizisi
- 11. satır: <string,int> sözlüğü
- 12-15. satırlar: 8. satırdaki string dizisinden sözlüğün başlatılması
- 17. satır: sözlüğün giriş sayısı
- 19. satır: sözlüğün anahtarları
- 21. satır: sözlüğün değerleri
- 29. satır: sözlükten bir girdinin silinmesi
- satır 41: sözlükte bir anahtarın aranması. Eğer mevcut değilse, TryGetValue yöntemi, value'e 0 değerini atayacaktır, çünkü value sayısal türdendir. Bu teknik, burada yalnızca 0 değerinin sözlükte bulunmadığı bilindiği için kullanılabilir.
Çalıştırma sonuçları şöyledir:
5.5. Metin dosyaları
5.5.1. StreamReader sınıfı
System.IO.StreamReader sınıfı, bir metin dosyasının içeriğini okumaya olanak tanır. Aslında, dosya olmayan akışları da işleyebilir. İşte bu sınıfın bazı özellikleri ve yöntemleri:
Oluşturucular
Özellikler
Yöntemler
İşte bir örnek:
using System;
using System.IO;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// çalıştırma dizini
Console.WriteLine("Répertoire d'exécution : "+Environment.CurrentDirectory);
string ligne = null;
StreamReader fluxInfos = null;
// dosya içeriğini okuma infos.txt
try {
// okuma 1
Console.WriteLine("Lecture 1----------------");
using (fluxInfos = new StreamReader("infos.txt")) {
ligne = fluxInfos.ReadLine();
while (ligne != null) {
Console.WriteLine(ligne);
ligne = fluxInfos.ReadLine();
}
}
// okuma 2
Console.WriteLine("Lecture 2----------------");
using (fluxInfos = new StreamReader("infos.txt")) {
Console.WriteLine(fluxInfos.ReadToEnd());
}
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : " + e.Message);
}
}
}
}
- 8. satır: çalıştırma dizinini gösterir
- 12. ve 27. satırlar: olası bir istisnayı yönetmek için bir try / catch.
- 15. satır: using flux=new StreamReader(...) yapısı, akış kullanıldıktan sonra onu açıkça kapatmak zorunda kalmamak için bir kolaylıktır. Bu kapatma işlemi, using kapsamından çıkıldığında otomatik olarak gerçekleştirilir.
- 15. satır: Okunan dosyanın adı infos.txt'tir. Bu, göreceli bir ad olduğundan, 8. satırda gösterilen yürütme dizininde aranacaktır. Eğer orada bulunmazsa, bir istisna atılır ve try / catch ile yönetilir.
- 16-20. satırlar: Dosya satır satır okunur
- 25. satır: Dosya tek seferde okunur
infos.txt dosyası şöyledir:
ve C# projesinin şu klasörüne yerleştirilmiştir:
![]() |
Ctrl-F5 tuşlarıyla proje çalıştırıldığında, bin/Release dosyasının yürütme dosyası olduğunu göreceğiz.
Çalıştırma işlemi şu sonuçları verir:
- satıra xx.txt dosya adını yazarsak şu sonuçları elde ederiz:
5.5.2. StreamWriter sınıfı
System.IO.StreamReader sınıfı, bir metin dosyasına yazmaya olanak tanır. StreamReader sınıfı gibi, bu sınıf da aslında dosya olmayan akışları işleyebilir. İşte bu sınıfın bazı özellikleri ve yöntemleri:
Oluşturucular
Özellikler
Yöntemler
Şu örneği ele alalım:
using System;
using System.IO;
namespace Chap3 {
class Program2 {
static void Main(string[] args) {
// çalıştırma dizini
Console.WriteLine("Répertoire d'exécution : " + Environment.CurrentDirectory);
string ligne = null; // bir metin satırı
StreamWriter fluxInfos = null; // metin dosyası
try {
// metin dosyasının oluşturulması
using (fluxInfos = new StreamWriter("infos2.txt")) {
Console.WriteLine("Mode AutoFlush : {0}", fluxInfos.AutoFlush);
// klavyeden girilen satırı okuma
Console.Write("ligne (rien pour arrêter) : ");
ligne = Console.ReadLine().Trim();
// girilen satır boş olmadığı sürece döngü
while (ligne != "") {
// satırı metin dosyasına yazma
fluxInfos.WriteLine(ligne);
// klavyeden yeni satırı okuma
Console.Write("ligne (rien pour arrêter) : ");
ligne = Console.ReadLine().Trim();
}//while
}
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : " + e.Message);
}
}
}
}
- 13. satır: Yine, akışı bir using(flux) işlemiyle açıkça kapatmak zorunda kalmamak için Close sözdizimini kullanıyoruz. Bu kapatma işlemi, using'ten çıkıldığında otomatik olarak gerçekleştirilir.
- 11. ve 27. satırlardaki try / catch neden kullanılıyor? 13. satırda, /rep1/rep2/ .../fichier şeklinde bir dosya adı verebiliriz; ancak /rep1/rep2/... gibi var olmayan bir yol belirtilirse, fichier dosyasının oluşturulması imkansız hale gelir. Bu durumda bir istisna atılır. Başka olası istisna durumları da vardır (disk dolu, yetki yetersizliği, ...)
Çalıştırma sonuçları şöyledir:
infos2.txt dosyası, projenin bin/Release klasöründe oluşturuldu:
![]() | ![]() |
5.6. İkili dosyalar
System.IO.BinaryReader ve System.IO.BinaryWriter sınıfları, ikili dosyaları okumak ve yazmak için kullanılır.
Şu uygulamayı ele alalım:
// pg, metin, ikili, günlük dosyalarının sözdizimi
// bir metin dosyası (text) okunur ve içeriği bir ikili dosyaya (bin) kaydedilir
// metin dosyası, isim : yaş biçiminde satırlara sahiptir; bunlar string ve int türlerinde bir yapıya kaydedilecektir
// (logs) bir log metin dosyasıdır
Metin dosyasının içeriği şöyledir:
Program şu şekildedir:
using System;
using System.IO;
// sözdizimi: pg metin bin logs
// bir metin dosyası (text) okunur ve içeriği bir ikili dosyaya (bin) kaydedilir
// metin dosyası, "ad: yaş" biçiminde satırlara sahiptir; bunlar bir string, int yapısına kaydedilecektir
// (logs) bir log metin dosyasıdır
namespace Chap3 {
class Program {
static void Main(string[] arguments) {
// 3 argüman gereklidir
if (arguments.Length != 3) {
Console.WriteLine("syntaxe : pg texte binaire log");
Environment.Exit(1);
}//if
// değişkenler
string ligne=null;
string nom=null;
int age=0;
int numLigne = 0;
char[] séparateurs = new char[] { ':' };
string[] champs=null;
StreamReader input = null;
BinaryWriter output = null;
StreamWriter logs = null;
bool erreur = false;
// metin dosyasını okuma - ikili dosyayı yazma
try {
// metin dosyasını okuma modunda açma
input = new StreamReader(arguments[0]);
// ikili dosyanın yazma modunda açılması
output = new BinaryWriter(new FileStream(arguments[1], FileMode.Create, FileAccess.Write));
// günlük dosyasını yazma modunda açma
logs = new StreamWriter(arguments[2]);
// metin dosyasını işleme
while ((ligne = input.ReadLine()) != null) {
// bir satır daha
numLigne++;
// boş satır mı?
if (ligne.Trim() == "") {
// yoksayılıyor
continue;
}
// "ad: yaş" satırı
champs = ligne.Split(séparateurs);
// 2 alan gerekiyor
if (champs.Length != 2) {
// hatayı günlüğe kaydediyoruz
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nombre de champs incorrect", numLigne, arguments[0]);
// sonraki satır
continue;
}//if
// 1. alan boş olmamalı
erreur = false;
nom = champs[0].Trim();
if (nom == "") {
// hatayı günlüğe kaydediyoruz
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un nom vide", numLigne, arguments[0]);
erreur = true;
}
// ikinci alan >=0 olan bir tamsayı olmalıdır
if (!int.TryParse(champs[1],out age) || age<0) {
// hata günlüğüne kaydedilir
logs.WriteLine("La ligne n° [{0}] du fichier [{1}] a un âge [{2}] incorrect", numLigne, arguments[0], champs[1].Trim());
erreur = true;
}//eğer
// hata yoksa, veriler ikili dosyaya yazılır
if (!erreur) {
output.Write(nom);
output.Write(age);
}
// sonraki satır
}//while
}catch(Exception e){
Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message);
} finally {
// dosyaları kapat
if(input!=null) input.Close();
if(output!=null) output.Close();
if(logs!=null) logs.Close();
}
}
}
}
BinaryWriter sınıfıyla ilgili işlemler üzerinde duralım:
- 34. satır: BinaryWriter nesnesi, işlem tarafından açılır
output=new BinaryWriter(new FileStream(arguments[1],FileMode.Create,FileAccess.Write));
Yapıcı argümanı bir akış (Stream) olmalıdır. Burada, aşağıda verilen bir dosyadan (FileStream) oluşturulan bir akış söz konusudur:
- (devamı)
- adı
- yapılacak işlem, burada dosyayı oluşturmak için FileMode.Create
- erişim türü; burada dosyaya yazma erişimi için FileAccess.Write
- 70-73. satırlar: yazma işlemleri
BinaryWriter sınıfı, farklı basit veri türlerini yazmak için Write yönteminin çeşitli üstü yazılmış versiyonlarına sahiptir
- satır 81: akışın kapatılması işlemi
Main yönteminin üç argümanı, projeye (özellikleri aracılığıyla) [1] verilir ve işlenecek metin dosyası bin/Release klasörüne yerleştirilir. [2]:
![]() |
Aşağıdaki [personnes1.txt] dosyası ile:
çalıştırma sonuçları şu şekildedir:
![]() |
- [1] dosyasında, bu şekilde oluşturulan [personnes1.bin] ikili dosyası ve [logs.txt] günlük dosyası bulunur. Günlük dosyasının içeriği şöyledir:
[personnes1.bin] ikili dosyasının içeriği, aşağıdaki program tarafından bize verilecektir. Bu program da üç argüman kabul eder:
// pg bin metin günlükleri sözdizimi
// bir ikili dosyayı (bin) okur ve içeriğini bir metin dosyasına (text) kaydeder
// ikili dosyanın yapısı string, int şeklindedir
// metin dosyası, "ad: yaş" biçiminde satırlara sahiptir
// logs, bir günlük metin dosyasıdır
Dolayısıyla tersi işlemi yapıyoruz. Bir ikili dosyayı okuyarak bir metin dosyası oluşturuyoruz. Oluşturulan metin dosyası orijinal dosyayla aynıysa, metin --> ikili --> metin dönüşümünün başarılı olduğunu anlarız. Kod şu şekildedir:
using System;
using System.IO;
// sözdizimi: pg, bin, metin, logs
// bin adlı ikili dosya okunur ve içeriği bir metin dosyasına (metin) kaydedilir
// ikili dosyanın yapısı string, int şeklindedir
// metin dosyası, "ad: yaş" biçiminde satırlardan oluşur
// logs, bir günlük metin dosyasıdır
namespace Chap3 {
class Program2 {
static void Main(string[] arguments) {
// 3 argüman gereklidir
if (arguments.Length != 3) {
Console.WriteLine("syntaxe : pg binaire texte log");
Environment.Exit(1);
}//if
// değişkenler
string nom = null;
int age = 0;
int numPersonne = 1;
BinaryReader input = null;
StreamWriter output = null;
StreamWriter logs = null;
bool fini;
// ikili dosya okuma - metin dosyası yazma
try {
// ikili dosyanın okuma modunda açılması
input = new BinaryReader(new FileStream(arguments[0], FileMode.Open, FileAccess.Read));
// metin dosyasını yazma modunda açma
output = new StreamWriter(arguments[1]);
// günlük dosyasını yazma modunda açma
logs = new StreamWriter(arguments[2]);
// ikili dosyanın işlenmesi
fini = false;
while (!fini) {
try {
// ad okuma
nom = input.ReadString().Trim();
// yaş okuma
age = input.ReadInt32();
// metin dosyasına yazma
output.WriteLine(nom + ":" + age);
// sonraki kişi
numPersonne++;
} catch (EndOfStreamException) {
fini = true;
} catch (Exception e) {
logs.WriteLine("L'erreur suivante s'est produite à la lecture de la personne n° {0} : {1}", numPersonne, e.Message);
}
}//while
} catch (Exception e) {
Console.WriteLine("L'erreur suivante s'est produite : {0}", e.Message);
} finally {
// dosyaları kapatma
if (input != null)
input.Close();
if (output != null)
output.Close();
if (logs != null)
logs.Close();
}
}
}
}
BinaryReader sınıfıyla ilgili işlemler üzerinde biraz duralım:
- 30. satır: BinaryReader nesnesi şu işlemle açılır:
input=new BinaryReader(new FileStream(arguments[0],FileMode.Open,FileAccess.Read));
Oluşturucunun argümanı bir akış (Stream) olmalıdır. Burada, bir dosyadan (FileStream) oluşturulan bir akış söz konusudur ve bu akış için şunlar verilmiştir:
- (devamı)
- adı
- yapılacak işlem, burada mevcut bir dosyayı açmak için FileMode.Open
- erişim türü; burada dosyaya okuma erişimi için FileAccess.Read
- 40. ve 42. satırlar: okuma işlemleri
BinaryReader sınıfı, çeşitli basit veri türlerini okumak için farklı yöntemlere sahiptir: ReadXX
- 60. satır: akış kapatma işlemi
personnes1.txt'i personnes1.bin'e, ardından personnes1.bin'i personnes2.txt2'e dönüştüren iki programı arka arkaya çalıştırırsak şu sonuçları elde ederiz:
![]() |
- [1]'e dönüştürüldü; proje, ikinci uygulamayı çalıştıracak şekilde yapılandırılmıştır
- [2]'te, Main'e aktarılan argümanlar
- [3]'te, uygulamanın çalıştırılmasıyla oluşturulan dosyalar yer alır.
[personnes2.txt] dosyasının içeriği şöyledir:
5.7. Düzenli ifadeler
System.Text.RegularExpressions.Regex sınıfı, düzenli ifadelerin kullanımına izin verir. Bunlar, bir karakter dizisinin biçimini test etmeyi sağlar. Böylece, bir tarihi temsil eden dizinin gerçekten gg/aa/yy biçiminde olup olmadığını doğrulayabiliriz. Bunun için bir şablon kullanılır ve dizi bu şablonla karşılaştırılır. Dolayısıyla bu örnekte, j, m ve a rakamlar olmalıdır. Geçerli bir tarih biçiminin şablonu "\d\d/\d\d/\d\d" şeklindedir; burada \d sembolü bir rakamı ifade eder. Şablonda kullanılabilecek semboller şunlardır:
Açıklama | |
Aşağıdaki karakteri özel karakter veya sabit karakter olarak işaretler. Örneğin, "n" karakteri "n" karakterine karşılık gelir. "\n" karakteri yeni satır karakterine karşılık gelir. "\\" dizisi "\" karakterine karşılık gelirken, "\(" karakteri "(" karakterine karşılık gelir. | |
Girişin başlangıcına karşılık gelir. | |
Girişin sonuna karşılık gelir. | |
Önceki karakterin sıfır kez veya birden fazla kez tekrarına karşılık gelir. Dolayısıyla, "zo*" "z" veya "zoo"ya karşılık gelir. | |
Önceki karakteri bir veya daha fazla kez eşleştirir. Dolayısıyla, "zo+" "zoo" ile eşleşir, ancak "z" ile eşleşmez. | |
Önceki karakterle sıfır veya bir kez eşleşir. Örneğin, "a?ve?" "lever" kelimesindeki "ve" ile eşleşir. | |
Satır sonu karakteri hariç, herhangi bir tekil karakterle eşleşir. | |
modèle'i arar ve eşleşmeyi saklar. Eşleşen alt dize, elde edilen Matches koleksiyonundan Item [0]...[n] kullanılarak çıkarılabilir. Parantez ( ) içindeki karakterlerle eşleşmeleri bulmak için "\(" veya "\)" kullanın. | |
x veya y ile eşleşir. Örneğin, "z|foot" correspond à "z" ou à "foot". "(z|f)oo" ifadesi "zoo" veya "foo" ile eşleşir. | |
n, negatif olmayan bir tam sayıdır. Tam olarak n çarpı karakter değerine karşılık gelir. Örneğin, "o{2}", "Bob," içindeki "o" harfine değil, "fooooot" içindeki ilk iki "o" harfine karşılık gelir. | |
n, negatif olmayan bir tamsayıdır. Karakterin en az n katına karşılık gelir. Örneğin, "o{2,}", "Bob" kelimesindeki "o" harfine değil, "fooooot" kelimesindeki tüm "o" harflerine karşılık gelir. "o{1,}", "o+" ile eşdeğerdir ve "o{0,}", "o*" ile eşdeğerdir. | |
m ve n, negatif olmayan tamsayılardır. Karakterin en az n ve en fazla m kez tekrarlandığı durumlara karşılık gelir. Örneğin, "o{1,3}", "foooooot" kelimesindeki ilk üç "o" harfine karşılık gelir ve "o{0,1}", "o?" ile eşdeğerdir. | |
Karakter kümesi. Belirtilen karakterlerden birine karşılık gelir. Örneğin, "[abc]", "plat" kelimesindeki "a" harfine karşılık gelir. | |
Negatif karakter kümesi. Belirtilmeyen tüm karakterlere karşılık gelir. Örneğin, "[^abc]", "plat" kelimesindeki "p" harfine karşılık gelir. | |
Karakter aralığı. Belirtilen dizideki tüm karakterlere karşılık gelir. Örneğin, "[a-z]", "a" ile "z" arasındaki tüm küçük harflere karşılık gelir. | |
Negatif karakter aralığı. Belirtilen dizide bulunmayan tüm karakterlere karşılık gelir. Örneğin, "[^m-z]", "m" ile "z" arasında bulunmayan tüm karakterlere karşılık gelir. | |
Bir kelimeyi temsil eden sınırla, başka bir deyişle bir kelime ile boşluk arasındaki konuma karşılık gelir. Örneğin, "er\b", "lever" kelimesindeki "er" ile eşleşir, ancak "verbe" kelimesindeki "er" ile eşleşmez. | |
Bir kelimeyi temsil etmeyen bir sınıra karşılık gelir. "en*t\B", "bien entendu" kelimesindeki "ent" kısmına karşılık gelir. | |
Bir rakamı temsil eden bir karaktere karşılık gelir. [0-9] ile eşdeğerdir. | |
Rakam olmayan bir karaktere karşılık gelir. [^0-9] ile eşdeğerdir. | |
Sayfa sonu karakterine karşılık gelir. | |
Yeni satır karakterine karşılık gelir. | |
Satır başı karakterine karşılık gelir. | |
Boşluk, sekme, sayfa sonu vb. dahil olmak üzere tüm boşluklara karşılık gelir. "[ \f\n\r\t\v]" ile eşdeğerdir. | |
Beyaz olmayan tüm boşluk karakterlerine karşılık gelir. "[^ \f\n\r\t\v]" ile eşdeğerdir. | |
Bir sekme karakterine karşılık gelir. | |
Dikey sekme karakterine karşılık gelir. | |
Bir kelimeyi temsil eden ve alt çizgi içeren herhangi bir karaktere karşılık gelir. "[A-Za-z0-9_]" ile eşdeğerdir. | |
Bir kelimeyi temsil etmeyen herhangi bir karaktere karşılık gelir. "[^A-Za-z0-9_]" ile eşdeğerdir. | |
num'e karşılık gelir; burada num pozitif bir tam sayıdır. Kaydedilmiş eşleşmelere atıfta bulunur. Örneğin, "(.)\1" iki ardışık aynı karaktere karşılık gelir. | |
n’e karşılık gelir; burada n, sekizlik bir kaçış değeridir. Sekizlik kaçış değerleri 1, 2 veya 3 basamaklı olmalıdır. Örneğin, "\11" ve "\011" her ikisi de bir sekme karakterine karşılık gelir. "\0011", "\001" ve "1"e eşittir. Sekizlik kaçış değerleri 256'yı aşmamalıdır. Aşılması durumunda, ifadede yalnızca ilk iki rakam dikkate alınır. ASCII kodlarının düzenli ifadelerde kullanılmasına olanak tanır. | |
n'e karşılık gelir; burada n onaltılık bir kaçış değeridir. Onaltılık kaçış değerleri mutlaka iki basamaklı olmalıdır. Örneğin, "\x41" "A" harfine karşılık gelir. "\x041" ise "\x04" ve "1" değerlerinin birleşimine eşittir. ASCII kodlarının düzenli ifadelerde kullanılmasına izin verir. |
Bir şablondaki öğe, 1 veya daha fazla kopya halinde bulunabilir. 1 rakamı temsil eden \d sembolüyle ilgili birkaç örneği ele alalım:
şablon | anlam |
\d | bir rakam |
\d? | 0 veya 1 rakam |
\d* | 0 veya daha fazla rakam |
\d+ | 1 veya daha fazla rakam |
\d{2} | 2 rakam |
\d{3,} | en az 3 rakam |
\d{5,7} | 5 ile 7 arasında rakam |
Şimdi, bir karakter dizisi için beklenen biçimi tanımlayabilen bir model düşünelim:
aranan dize | model |
gg/mm/yy formatında bir tarih | \d{2}/\d{2}/\d{2} |
hh:mm:ss biçiminde bir saat | \d{2}:\d{2}:\d{2} |
işaretsiz bir tamsayı | \d+ |
boş olabilir bir boşluk dizisi | \s* |
önünde veya arkasında boşluk bulunabilen işaretsiz bir tamsayı | \s*\d+\s* |
işareti olan bir tamsayı; başında veya sonunda boşluk olabilir | \s*[+|-]?\s*\d+\s* |
önünde veya arkasında boşluk bulunabilen işaretsiz bir gerçek sayı | \s*\d+(.\d*)?\s* |
işareti olan veya olmayan bir gerçek sayı; başında veya sonunda boşluk olabilir | \s*[+|]?\s*\d+(.\d*)?\s* |
juste kelimesini içeren bir dize | \bjuste\b |
Dizgide kalıbın nerede aranacağını belirtebiliriz:
şablon | anlam |
^şablon | model, dizgenin başında yer alır |
model$ | şablon dizgiyi sonlandırır |
^desen$ | şablon dizgiyi başlatır ve bitirir |
desen | desen, dizgenin başından başlayarak her yerinde aranır. |
aranan dize | desen |
ünlem işaretiyle biten bir dize | !$ |
nokta ile biten bir dize | \.$ |
// dizisiyle başlayan bir dize | ^// |
yalnızca bir kelimeden oluşan ve isteğe bağlı olarak öncesinde veya sonrasında boşluklar bulunan bir dize | ^\s*\w+\s*$ |
önünde veya arkasında boşluk olabilecek iki kelimeden oluşan bir dize | ^\s*\w+\s*\w+\s*$ |
secret kelimesini içeren bir dize | \bsecret\b |
Bir şablonun alt kümeleri "çıkarılabilir". Böylece, bir dizgenin belirli bir şablona uyup uymadığını kontrol etmekle kalmaz, aynı zamanda bu dizgede parantezlerle çevrelenmiş şablonun alt kümelerine karşılık gelen öğeleri de çıkarabiliriz. Örneğin, gg/aa/yyyy biçiminde bir tarih içeren bir dizgiyi analiz ediyorsak ve bu tarihin gg, aa, yyyy öğelerini de ayıklamak istiyorsak, (\d\d)/(\d\d)/(\d\d) şablonunu kullanırız.
5.7.1. Bir dizgenin belirli bir modele uyup uymadığını kontrol etme
Regex türü bir nesne şu şekilde oluşturulur:
Şablon düzenli ifade oluşturulduktan sonra, IsMatch yöntemi kullanılarak karakter dizileriyle karşılaştırılabilir:
İşte bir örnek:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program {
static void Main(string[] args) {
// bir düzenli ifade şablonu
string modèle1 = @"^\s*\d+\s*$";
Regex regex1 = new Regex(modèle1);
// bir örneği şablonla karşılaştırma
string exemplaire1 = " 123 ";
if (regex1.IsMatch(exemplaire1)) {
Console.WriteLine("[{0}] correspond au modèle [{1}]", exemplaire1, modèle1);
} else {
Console.WriteLine("[{0}] ne correspond pas au modèle [{1}]", exemplaire1, modèle1);
}//if
string exemplaire2 = " 123a ";
if (regex1.IsMatch(exemplaire2)) {
Console.WriteLine("[{0}] correspond au modèle [{1}]", exemplaire2, modèle1);
} else {
Console.WriteLine("[{0}] ne correspond pas au modèle [{1}]", exemplaire2, modèle1);
}//if
}
}
}
ve çalıştırma sonuçları:
5.7.2. Bir dizede bir deseni içeren tüm örnekleri bulma
Matches yöntemi, bir dizedeki bir desene uyan öğeleri almayı sağlar:
MatchCollection sınıfının, koleksiyondaki öğe sayısını gösteren Count özelliği vardır. résultats bir MatchCollection nesnesi ise, [i] bu koleksiyonun i'inci elemanıdır ve Match türündedir. Match sınıfı, aşağıdakiler dahil olmak üzere çeşitli özelliklere sahiptir:
- Value: Match, nesnesinin değeri, yani modele karşılık gelen bir öğe
- Index: Elemanın taranan dizede bulunduğu konum
Aşağıdaki örneği inceleyelim:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program2 {
static void Main(string[] args) {
// örnekteki kalıbın birden fazla tekrarı
string modèle2 = @"\d+";
Regex regex2 = new Regex(modèle2);
string exemplaire3 = " 123 456 789 ";
MatchCollection résultats = regex2.Matches(exemplaire3);
Console.WriteLine("Modèle=[{0}],exemplaire=[{1}]", modèle2, exemplaire3);
Console.WriteLine("Il y a {0} occurrences du modèle dans l'exemplaire ", résultats.Count);
for (int i = 0; i < résultats.Count; i++) {
Console.WriteLine("[{0}] trouvé en position {1}", résultats[i].Value, résultats[i].Index);
}//for
}
}
}
- 8. satır: Aranan şablon bir sayı dizisidir
- 10. satır: Bu şablonun arandığı dize
- 11. satır: exemplaire3 dizisindeki, modèle2 desenine uyan tüm öğeler alınır
- 14-16. satırlar: Bunlar ekrana yazdırılır
Programın çalıştırılması sonucunda elde edilen sonuçlar şunlardır:
5.7.3. Bir şablonun parçalarını alma
Bir şablonun alt kümeleri "alınabilir". Böylece, bir dizgenin belirli bir şablona uyup uymadığını doğrulamakla kalmaz, aynı zamanda bu dizgeden şablonun parantezlerle çevrili alt kümelerine karşılık gelen öğeleri de alabiliriz. Örneğin, gg/aa/yyyy tarihini içeren bir dizgiyi analiz ediyorsak ve bu tarihin gg, aa, yyyy öğelerini de ayıklamak istiyorsak, (\d\d)/(\d\d)/(\d\d) şablonunu kullanırız.
Şu örneği inceleyelim:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program3 {
static void Main(string[] args) {
// şablondaki öğelerin yakalanması
string modèle3 = @"(\d\d):(\d\d):(\d\d)";
Regex regex3 = new Regex(modèle3);
string exemplaire4 = "Il est 18:05:49";
// şablon doğrulaması
Match résultat = regex3.Match(exemplaire4);
if (résultat.Success) {
// örnek, şablona uyuyor
Console.WriteLine("L'exemplaire [{0}] correspond au modèle [{1}]",exemplaire4,modèle3);
// parantez grupları görüntülenir
for (int i = 0; i < résultat.Groups.Count; i++) {
Console.WriteLine("groupes[{0}]=[{1}] trouvé en position {2}",i, résultat.Groups[i].Value,résultat.Groups[i].Index);
}//for
} else {
// örnek, şablona uymuyor
Console.WriteLine("L'exemplaire[{0}] ne correspond pas au modèle [{1}]", exemplaire4, modèle3);
}
}
}
}
Bu programın çalıştırılması sonucunda aşağıdaki sonuçlar elde edilir:
Yenilik, 12-19. satırlarda yer almaktadır:
- 12. satır: exemplaire4 dizesi, Match yöntemi aracılığıyla regex3 şablonuyla karşılaştırılır. Bu yöntem, daha önce tanıtılmış olan bir Match nesnesini döndürür. Burada bu sınıfın iki yeni özelliğini kullanıyoruz:
- Success (13. satır): eşleşme olup olmadığını gösterir
- Groups (17. ve 18. satırlar):
- Groups[0]'in, şablona karşılık gelen dize kısmına karşılık geldiği koleksiyon
- Groups[i] (i>=1), i numaralı parantez grubuna karşılık gelir
résultat, Match türündeyse, résultats.Groups, GroupCollection türündedir ve résultats.Groups[i], Group türündedir. Group sınıfının burada kullandığımız iki özelliği vardır:
- Value (18. satır): Group nesnesinin değeri; bu, parantez içindeki içeriğe karşılık gelen öğedir
- Index (satır 18): Elemanın taranan dizede bulunduğu konum
5.7.4. Bir alıştırma programı
Bir dizgenin belirli bir şablona uyup uymadığını kontrol etmeyi sağlayan düzenli ifadeyi bulmak bazen gerçek bir zorluktur. Aşağıdaki program bu konuda alıştırma yapmanıza olanak tanır. Program, bir şablon ve bir dizge ister ve dizgenin şablona uyup uymadığını belirtir.
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program4 {
static void Main(string[] args) {
// veriler
string modèle, chaine;
Regex regex = null;
MatchCollection résultats;
// kullanıcıdan, bu örnekle karşılaştırılacak şablonlar ve örnekler isteniyor
while (true) {
// şablon isteniyor
Console.Write("Tapez le modèle à tester ou rien pour arrêter :");
modèle = Console.In.ReadLine();
// bitti mi?
if (modèle.Trim() == "")
break;
// düzenli ifade oluşturuluyor
try {
regex = new Regex(modèle);
} catch (Exception ex) {
Console.WriteLine("Erreur : " + ex.Message);
continue;
}
// kullanıcıdan şablonla karşılaştırılacak örnekleri istiyoruz
while (true) {
Console.Write("Tapez la chaîne à comparer au modèle [{0}] ou rien pour arrêter :", modèle);
chaine = Console.ReadLine();
// bitti mi?
if (chaine.Trim() == "")
break;
// karşılaştırma yapılıyor
résultats = regex.Matches(chaine);
// başarılı mı?
if (résultats.Count == 0) {
Console.WriteLine("Je n'ai pas trouvé de correspondances");
continue;
}//if
// modele uyan öğeler görüntülenir
for (int i = 0; i < résultats.Count; i++) {
Console.WriteLine("J'ai trouvé la correspondance [{0}] en position [{1}]", résultats[i].Value, résultats[i].Index);
// alt öğeler
if (résultats[i].Groups.Count != 1) {
for (int j = 1; j < résultats[i].Groups.Count; j++) {
Console.WriteLine("\tsous-élément [{0}] en position [{1}]", résultats[i].Groups[j].Value, résultats[i].Groups[j].Index);
}
}
}
}
}
}
}
}
İşte bir çalışma örneği:
5.7.5. Split yöntemi
Bu yöntemi daha önce String dersinde görmüştük:
|
Regex sınıfındaki Split yöntemi, ayırıcıyı bir şablona göre ifade etmemizi sağlar:
|
Örneğin, bir metin dosyasında alan1, alan2, ..., alann şeklinde satırlar olduğunu varsayalım. Alanlar virgülle ayrılmıştır, ancak virgülün önünde veya arkasında boşluklar olabilir. Bu durumda, string sınıfındaki Split yöntemi uygun değildir. Çözümü, RegEx yönteminde bulabiliriz. Okunan satır ligne ise, alanlar şu şekilde elde edilebilir:
kullanılarak elde edilebilir; aşağıdaki örnekte gösterildiği gibi:
using System;
using System.Text.RegularExpressions;
namespace Chap3 {
class Program5 {
static void Main(string[] args) {
// bir satır
string ligne = "abc , def , ghi";
// bir şablon
Regex modèle = new Regex(@"\s*,\s*");
// satırın alanlara ayrılması
string[] champs = modèle.Split(ligne);
// görüntüleme
for (int i = 0; i < champs.Length; i++) {
Console.WriteLine("champs[{0}]=[{1}]", i, champs[i]);
}
}
}
}
Çalıştırma sonuçları:
5.8. Örnek uygulama - V3
3.6 (sürüm 1) ve 4.10 (sürüm 2) paragraflarında incelenen uygulamayı tekrar ele alıyoruz.
İncelenen son sürümde, vergi hesaplaması AbstractImpot soyut sınıfında yapılıyordu:
namespace Chap2 {
abstract class AbstractImpot : IImpot {
// vergi hesaplaması için gerekli vergi dilimleri
// harici bir kaynaktan alınır
protected TrancheImpot[] tranchesImpot;
// vergi hesaplaması
public int calculer(bool marié, int nbEnfants, int salaire) {
// pay sayısının hesaplanması
decimal nbParts;
if (marié) nbParts = (decimal)nbEnfants / 2 + 2;
else nbParts = (decimal)nbEnfants / 2 + 1;
if (nbEnfants >= 3) nbParts += 0.5M;
// vergilendirilebilir gelir ve aile katsayısı hesaplaması
decimal revenu = 0.72M * salaire;
decimal QF = revenu / nbParts;
// vergi hesaplaması
tranchesImpot[tranchesImpot.Length - 1].Limite = QF + 1;
int i = 0;
while (QF > tranchesImpot[i].Limite) i++;
// sonuç döndürme
return (int)(revenu * tranchesImpot[i].CoeffR - nbParts * tranchesImpot[i].CoeffN);
}//hesapla
}//sınıf
}
- satırdaki calculer yöntemi, 35. satırdaki tranchesImpot tablosunu kullanmaktadır; bu tablo, AbstractImpot sınıfı tarafından başlatılmamıştır. Bu nedenle bu yöntem soyuttur ve kullanılabilir hale gelmesi için türetilmesi gerekir. Bu başlatma işlemi, türetilmiş HardwiredImpot sınıfı tarafından gerçekleştiriliyordu:
using System;
namespace Chap2 {
class HardwiredImpot : AbstractImpot {
// vergi hesaplaması için gerekli veri tabloları
decimal[] limites = { 4962M, 8382M, 14753M, 23888M, 38868M, 47932M, 0M };
decimal[] coeffR = { 0M, 0.068M, 0.191M, 0.283M, 0.374M, 0.426M, 0.481M };
decimal[] coeffN = { 0M, 291.09M, 1322.92M, 2668.39M, 4846.98M, 6883.66M, 9505.54M };
public HardwiredImpot() {
// vergi dilimleri tablosunun oluşturulması
tranchesImpot = new TrancheImpot[limites.Length];
// doldurma
for (int i = 0; i < tranchesImpot.Length; i++) {
tranchesImpot[i] = new TrancheImpot { Limite = limites[i], CoeffR = coeffR[i], CoeffN = coeffN[i] };
}
}
}// sınıf
}// ad alanı
Yukarıda, vergi hesaplaması için gerekli veriler sınıf koduna "sabit" olarak yerleştirilmişti. Örneğin yeni sürümünde ise bu veriler bir metin dosyasına yerleştirilmiştir:
4962:0:0
8382:0,068:291,09
14753:0,191:1322,92
23888:0,283:2668,39
38868:0,374:4846,98
47932:0,426:6883,66
0:0,481:9505,54
Bu dosyanın işlenmesi sırasında istisnalar ortaya çıkabileceğinden, bunları yönetmek için özel bir sınıf oluşturuyoruz:
using System;
namespace Chap3 {
class FileImpotException : Exception {
// hata kodları
[Flags]
public enum CodeErreurs { Acces = 1, Ligne = 2, Champ1 = 4, Champ2 = 8, Champ3 = 16 };
// hata kodu
public CodeErreurs Code { get; set; }
// yapıcılar
public FileImpotException() {
}
public FileImpotException(string message)
: base(message) {
}
public FileImpotException(string message, Exception e)
: base(message,e) {
}
}
}
- 4. satır: FileImpotException sınıfı, Exception sınıfından türetilmiştir. Bu sınıf, veri metin dosyasının işlenmesi sırasında ortaya çıkan tüm hataları kaydetmek için kullanılacaktır.
- 7. satır: Hata kodlarını temsil eden bir sıralama:
- Acces: veri metin dosyasına erişim hatası
- Ligne: Satırda beklenen üç alan bulunmuyor
- Champ1: 1 numaralı alan hatalı
- Champ2: 2 numaralı alan hatalı
- Champ3: 3 numaralı alan hatalı
Bu hatalardan bazıları bir arada görülebilir (Champ1, Champ2, Champ3). Bu nedenle, CodeErreurs numaralı sıralamaya [Flags] özniteliği eklenmiştir; bu, sıralamadaki farklı değerlerin 2'nin kuvvetleri olması gerektiğini belirtir. 1 ve 2 numaralı alanlarda bir hata olması durumunda, Champ1 | Champ2 hata kodu verilir.
- 10. satır: Code otomatik özelliği, hata kodunu kaydedecektir.
- 15. satır: Bir hata mesajını parametre olarak geçirerek FileImpotException nesnesini oluşturmaya yarayan bir oluşturucu.
- 18. satır: Bir hata mesajını ve hataya neden olan istisnayı parametre olarak alarak FileImpotException nesnesini oluşturmaya yarayan bir oluşturucu.
AbstractImpot sınıfının tranchesImpot dizisini başlatan sınıf artık şu şekildedir:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace Chap3 {
class FileImpot : AbstractImpot {
public FileImpot(string fileName) {
// veriler
List<TrancheImpot> listTranchesImpot = new List<TrancheImpot>();
int numLigne = 1;
// istisna
FileImpotException fe = null;
// fileName dosyasının içeriğini satır satır okuma
Regex pattern = new Regex(@"s*:\s*");
// başlangıçta hata yok
FileImpotException.CodeErreurs code = 0;
try {
using (StreamReader input = new StreamReader(fileName)) {
while (!input.EndOfStream && code == 0) {
// geçerli satır
string ligne = input.ReadLine().Trim();
// boş satırlar atlanır
if (ligne == "") continue;
// satır, aşağıdakilerle ayrılmış üç alana bölünmüştür:
string[] champsLigne = pattern.Split(ligne);
// 3 alan var mı?
if (champsLigne.Length != 3) {
code = FileImpotException.CodeErreurs.Ligne;
}
// 3 alanın dönüştürülmesi
decimal limite = 0, coeffR = 0, coeffN = 0;
if (code == 0) {
if (!Decimal.TryParse(champsLigne[0], out limite)) code = FileImpotException.CodeErreurs.Champ1;
if (!Decimal.TryParse(champsLigne[1], out coeffR)) code |= FileImpotException.CodeErreurs.Champ2;
if (!Decimal.TryParse(champsLigne[2], out coeffN)) code |= FileImpotException.CodeErreurs.Champ3; ;
}
// hata mı?
if (code != 0) {
// hatk not ediliyor
fe = new FileImpotException(String.Format("Ligne n° {0} incorrecte", numLigne)) { Code = code };
} else {
// yeni vergi dilimini kaydediyoruz
listTranchesImpot.Add(new TrancheImpot() { Limite = limite, CoeffR = coeffR, CoeffN = coeffN });
// sonraki satır
numLigne++;
}
}
}
// listImpot listesi tranchesImpot tablosuna aktarılıyor
if (code == 0) {
// listImpot listesi tranchesImpot tablosuna aktarılır
tranchesImpot = listTranchesImpot.ToArray();
}
} catch (Exception e) {
// hata kaydedilir
fe= new FileImpotException(String.Format("Erreur lors de la lecture du fichier {0}", fileName), e) { Code = FileImpotException.CodeErreurs.Acces };
}
// hatayı bildirmeli miyiz?
if (fe != null) throw fe;
}
}
}
- 7. satır: FileImpot sınıfı, sürüm 2'de HardwiredImpot sınıfının yaptığı gibi AbstractImpot sınıfından türetilmiştir.
- 9. satır: FileImpot sınıfının oluşturucusunun görevi, temel sınıfı olan AbstractImpot'in trancheImpot alanını başlatmaktır. Bu oluşturucu, verileri içeren metin dosyasının adını parametre olarak alır.
- 11. satır: AbstractImpot temel sınıfının tranchesImpot alanı, parametre olarak geçirilen filename dosyasındaki verilerle doldurulması gereken bir dizidir. Metin dosyasının okunması sıralıdır. Satır sayısı, dosyanın tamamı okunduktan sonra öğrenilebilir. Bu nedenle tranchesImpot dizisinin boyutunu önceden belirleyemeyiz. Verileri geçici olarak listTranchesImpot genel listesinde saklayacağız.
TrancheImpot türünün bir yapı olduğunu hatırlatmak isteriz:
namespace Chap3 {
// bir vergi dilimi
struct TrancheImpot {
public decimal Limite { get; set; }
public decimal CoeffR { get; set; }
public decimal CoeffN { get; set; }
}
}
- 14. satır: fe türü FileImpotException, metin dosyasının işlenmesinde meydana gelebilecek olası bir hatayı kapsüllemek için kullanılır.
- 16. satır: Metin dosyasındaki bir champ1:champ2:champ3 satırındaki alan ayırıcısının düzenli ifadesi. Alanlar, önünde ve arkasında herhangi bir sayıda boşluk bulunan : karakteriyle ayrılır.
- 18. satır: Hata durumunda hata kodu
- 20. satır: metin dosyasının StreamReader ile işlenmesi
- 21. satır: Okunacak satır kaldığı ve hata oluşmadığı sürece döngü devam eder
- 27. satır: Okunan satır, 16. satırdaki düzenli ifade kullanılarak alanlara bölünür
- 29-31. satırlar: satırın üç alana sahip olduğu kontrol edilir; olası bir hata kaydedilir
- 33-38. satırlar: Üç dize, üç ondalık sayıya dönüştürülür; olası hatalar kaydedilir
- 40-43. satırlar: Hata varsa, FileImpotException türünde bir istisna oluşturulur.
- 44-47. satırlar: Hata yoksa, mevcut satırdan alınan veriler kaydedildikten sonra metin dosyasının bir sonraki satırının okunmasına geçilir.
- satır 52-55: while çıkışında, listTranchesImpot genel listesindeki veriler, AbstractImpot temel sınıfının tranchesImpot tablosuna kopyalanır. Bunun, geliştiricinin amacının bu olduğu hatırlatılmalıdır.
- 56-59. satırlar: Olası bir istisnanın yönetimi. Bu istisna, FileImpotException türünde bir nesne içinde kapsüllenir.
- 61. satır: 18. satırdaki fe istisnası başlatılmışsa, bu istisna tetiklenir.
C# projesinin tamamı şu şekildedir:
![]() |
- [1] içinde: projenin tamamı
- [2,3]'te: [DataImpot.txt] ve [2] dosyalarının özellikleri. [Copy to Output Directory] ve [3] özellikleri "always" olarak ayarlanır. Bu ayar sayesinde, [DataImpot.txt] dosyası her çalıştırmada bin/Release klasörüne (Release modu) veya bin/Debug klasörüne (Debug modu) kopyalanır. Yürütülebilir dosya bu klasörlerde dosyayı arar.
- [4] dosyasında: [DataImpotInvalide.txt] dosyası için de aynı işlem yapılır.
[DataImpot.txt] dosyasının içeriği şöyledir:
4962:0:0
8382:0,068:291,09
14753:0,191:1322,92
23888:0,283:2668,39
38868:0,374:4846,98
47932:0,426:6883,66
0:0,481:9505,54
[DataImpotInvalide.txt] dosyasının içeriği şöyledir:
[Program.cs] test programı değişmemiştir: Bu, 2. sürümün 4.10. paragrafındaki programdır, ancak şu farkla:
using System;
namespace Chap3 {
class Program {
static void Main() {
...
// bir nesnenin oluşturulması IImpot
IImpot impot = null;
try {
// bir nesnenin oluşturulması IImpot
impot = new FileImpot("DataImpot.txt");
} catch (FileImpotException e) {
// hata görüntüleme
string msg = e.InnerException == null ? null : String.Format(", Exception d'origine : {0}", e.InnerException.Message);
Console.WriteLine("L'erreur suivante s'est produite : [Code={0},Message={1}{2}]", e.Code, e.Message, msg == null ? "" : msg);
// programın durdurulması
Environment.Exit(1);
}
// sonsuz döngü
while (true) {
...
}//while
}
}
}
- 8. satır: impot nesnesi, IImpot arayüz türündedir
- 11. satır: impot nesnesinin, FileImpot türündeki bir nesneyle örneklendirilmesi. Bu işlem, 9., 12. ve 18. satırlardaki try / catch bloğu tarafından yönetilen bir istisna oluşturabilir.
İşte bazı çalıştırma örnekleri:
[DataImpot.txt] dosyası ile
[xx] dosyası mevcut değilken
[DataImpotInvalide.txt] dosyası ile






























