Cumartesi, Ekim 27, 2007

C# ile EXIF Bilgilerini Okuma.

JPG dosyalarının içinde fotoğraf ile ilgili birçok bilgi bulunur. EXIF bilgileri genellikle fotoğrafın hangi ayarlarda çekildiğini anlamak için kullanılsa da JPEG dosyası içerisinde çok daha detaylı bilgiler bulunmaktadır. C# ile bu bilgileri okumak çok kolaydır. Image sınıfı işe yarayacak temel fonksiyonları içerir. Image.PropertyIdList özelliği dosyaya gömülü bilgilerin Id numaralarını içeren bir liste döndürür. PropertyItem sınıfının ilgili EXIF bilgisini ve değerini okumak için kullanacağımız dört özelliği vardır. Id özelliği ilgili bilginin standart numarasıdır. Örneğin Id değeri "0x010F" olan PropertyItem nesnesinden Fotoğrafın çekildiği kameranın adını okuyabiliriz. Bunu okuayabilmek için Value özelliğini kullanırız. Value özelliği, uzunluğunu Len özelliğinden okuyabileceğimiz bir Byte Array'dir. Value değerinin tipini ise Type özelliğinden okuyabiliriz. Örneğin Type 2 ise bilgi ASCII tipinde, 3 ise Short Integer tipindedir.

Hangi Id'nin hangi değere karşılık geldiğini bilebilmek için Mark Michaelis isimli arkadaşın GDIConstants.h dosyasından ayıklayarak hazırladığı ImagePropertyIDTags Enumeration sınıfını kullanacağız. Uzun bir dosya olduğu için burada vermeyeceğim. Buradan indirebilirsiniz. Aynı dosya içersinde Type değerinin neye karşılık geldiğini anlayabileceğimiz bir ImagePropertyTypes Enumeration sınıfı da var. Örnek kodumuzda bu Enumeration değerlerinden faydalanacağız. Kodumuz vereceğimiz dosya isminden JPEG dosyayı yükleyerek özelliklerini bir String listesi olarak döndürecek.

static class ExifExtractor
{
public static IList ExifListesiniAl(string dosyaAdi)
{
IList degerListesi = new List();
Image imaj = new Bitmap(dosyaAdi);
foreach (int id in imaj.PropertyIdList)
{
string deger = string.Empty;
try
{
PropertyItem ozellik = imaj.GetPropertyItem(id);
for (int i = 0; i < (ozellik.Len - 1); i++)

{
if (((char)ozellik.Value[i]) != '\n')
deger += (char)ozellik.Value[i];
}
deger = string.Format("{0} = {1}", (ImagePropertyIDTags)ozellik.Id, deger);
}
catch (Exception e)
{
deger = string.Format("{0} numaralı özelliği okurken {1} hatası oldu.", id, e.Message);
}
degerListesi.Add(deger);
}
return degerListesi;
}
}

Bu basit örnek kodu sadece olayın temel mantığını gösterebilmek için verdim. Artık JPEG dosyasından okumak istediğiniz değerleri nerede kullanmak istiyorsanız ona göre değiştirebilirsiniz.

Pazar, Ekim 21, 2007

Design Patterns'a Hakim Eleman Aranıyor

Bugün gazetedeki iş ilanlarını incelerken programcı arayan bir şirketin gazeteye verdiği ilan gözüme çarptı. Aranılan nitelikler arasında "Object Oriented Design ve Patterns'a hakim" diye bir madde vardı.

Design Patterns'a hakim olmak nasıl birşeydir? Neden şirketler Desing Patterns'a hakim adam ararlar? Design Patterns'a hakim olmak neyi ispatlar? Bu hakimiyet nasıl ölçülür?

Tasarım kalıpları temelde programcılığa yeni başlayan kişilerin Nesne Yönelimli Programlama'nın ilkelerini daha kolay öğrenebilmeleri için düşünülmüştür. Nihayetinde teoridir, kalıptır, sık yaşanın NYP problemlerine getirilen çözüm önerileridir. Pratikte çok da işe yaramaz çünkü gerçek hayat problemleri genellikle bir kalıba uymaz. Tecrübeli bir NYP programcısının yazacağı kod ilgili kalıbın tarifini bilse de bilmese de zaten çok farklı olmaz. Tecrübesiz programcılar genellikle çalışan kodu sırf iyi olacağını düşündüğü için kalıba uydurmaya çalışır ve gerekenden fazla iş yapar. Biraz da espiriyle karışık bir Hello World uygulaması örneği.

Bir kurs ilanında Tasarım Kalıbından bahsedilmesi normaldir ama iş ilanında bu niteliği garipsedim.

Perşembe, Ekim 18, 2007

Bilgisayar Programı Yatırımı

Neden bilgisayar programı satın alırız?

Bilgisayar programı satın almamızın birçok farklı nedeni olabilir. Rakiplerimizin satın aldığını duymuş olabiliriz, bir pazarlamacının anlattığı özelliklerden etkilenebiliriz, büyük bir şirketin yeni geçtiği programın ne kadar başarılı olduğunu okumuşuzdur, işyeri komşumuz aldığı müthiş programdan bahsetmiş olabilir veya bir reklamdan etkilenmiş olabiliriz. Hatta büyük firmalarla aynı programı kullanarak onlarla aynı kategoride değerlendirileceğimizi bile düşünüyor olabiliriz.

Gerçekte bu yollardan hiçbirisi bize faydalı olacak olan programı seçmemizde faydalı olmaz. Program bir sorunu çözmelidir. Her işyerinin çözüm bekleyen kendine özgü benzersiz sorunları vardır. Bizim için önemli olan işyerimizin çalışma şeklini anlamamız, gereksinimleri belirlememiz ve yaşadığımız sorunların programla nasıl çözülebileceğine dair fikirler edinmemizdir. Genellikle bunları yapmak yerine satın almayı düşündüğümüz programların inanılmaz özellikleriyle veya kulaktan dolma başarı hikayelerle ilgileniriz. Aslında hiç bir program pazarlamacısı işimizle ilgili detaylı incelemeler yaparak programın sorunlarımızı nasıl çözeceğini anlatmaz. Onun yerine XYZ mağazalar zincirinde nasıl beğenilerek kullanıldığını anlatır. XYZ'nin sorununu çözen bizim sorunumuzu haydi haydi çözer değil mi? Ne yazık ki değil. Sorunumuzu tam anlamadan çözüme ulaşmamız mümkün değildir. Birinci adım programa neden ihtiyaç duyduğumuzu anlamak olmalıdır.

İkinci adım gereksinimlerimizi karşılayan en iyi çözümü tespit etmek olacaktır. Burada aslında işler biraz karışıktır. Pazarlamacılar aynı şeylerden bahsettikleri ve aynı sorunları çözdüklerini anlattıkları halde yüz dolardan milyon dolarlara kadar çeşitli fiyatlarla karşımıza çıkarlar. Hatta daha da ilginci bilgiç bir arkadaşımız aynı işi yapan ücretsiz bir program olduğundan da bahseder. Alternatif programların tam olarak ne yapabildiğinin ve işimize ne kadar uygun olduğunun araştırılması önemlidir.

Diyelim ki gereksinimlerimizi güzelce tespit ettik ve ihtiyaçlarımızı tam olarak karşılayan programa karar vererek satın aldık. Artık bir yan gelip yatma zamanı geldi değil mi?

Ne yazık ki sadece para harcayarak en iyiyi yapabilmek mümkün değildir. Program çalışanların bir kısmının yaptığı işleri üstlenebilir ancak kullanacak birileri olmadan program hiç bir işe yaramaz. Aslına onu doğru kullanacak birileri olmadan işe yaramaz. Öncelikle programı doğru kullanabileceğimiz şekilde iyice öğrenmemiz gerekir. Aslında bir de programın doğru şekilde çalışmasının nasıl sağlanacağını da öğrenmemiz gerekir. Bir programın doğru çalışması birçok yan faktöre bağlıdır.

Belki de en önemlisi satın aldığımız programı işleri yürütme sorumlusu olarak değil yaptığımız işlerin birkısmını devredebileceğimiz bir yardımcı olarak görmeliyiz.

Pazartesi, Ekim 08, 2007

.Net Kaynak Kodları Açılıyor

Microsoft Visual Studio 2008 ve .Net Framework 3.5 ile birlikte .Net kütüphanelerinin kaynak kodlarını açıyor. Kaynak kodları doğrudan indirilebilecek veya VS2008'e yapılacak bir ayarla otomatik olarak ihtiyaç oldukça indirilecek. Kaynak kodların kullanımı daha önceden duymamış olduğum Microsoft Reference Licence ile lisanslanmış durumda. Bu şu anlama geliyor.

Ne maksatla olursa olsun:
  • Kaynak kodlar üzerinde değişiklik yapılamaz.
  • Kaynak kodlar hata düzeltme için kullanılamaz.
  • Kodlara yeni özellikler eklenemez.
Kaynak kodlar sadece koda bakma ve hata ayıklama maksatlı açılıyor. Tabi kodların hata ayıklayıcıya entegre edilmesi hata ayıklama anlamında büyük avantaj. Lisansa göre yakaladığımız hata .Net kodları içinde olsa dahi kod üzerinde değişiklik yapamıyoruz. Microsoft modifiye edilmiş .Net kütüphanesi yakalarsa geliştiricisinin canını yakma gücü elince var. Hata gördüğümüzde düzeltmek yerine sıkıntıyı .Net geliştiricilerine iletebiliyoruz. Böyle bir avantajımız (!) var :)

Bloglarda dönen dedikodulara göre bu hareket biraz da Mono projesinin önünü kesmek için yapılmış. Mono bildiğiniz gibi .Net programlarının Windows, Linux, Solaris, vb. gibi işletim sistemlerinde çalışmasını sağlıyor. Bir nevi .Net Framework'ün açık kaynaklı Linux klonu. Tabii Mono kodları üzerinde dilediğiniz değişikliği yapabiliyorsunuz. Rivayet odur ki; Microsoft Mono'da, .Net Framework'den aşırılmış kodlar olduğunu iddia ediyor. Microsoft kodları yayınladıktan sonra bu konuda Mono'nun üzerine gider mi onu da zaman gösterecek. Zaman ne gösterirse göstersin açık kaynak zihniyetinin Microsoft'a büyük zarar verdiği tartışılamaz bir gerçek.

Cumartesi, Ekim 06, 2007

Aklın Yeni Sınırları

Kitabevinin iş kitapları bölümünde yaklaşık yarım saat geçirmiş, bu sefer düzgün bir kitap bulamayacağıma karar vermiştim. Bu kitap tam vazgeçmek üzereyken gözüme çarptı. Arkasını çevirdiğimde bu tür kitaplarıyla ünlü Tom Peters ve Seth Godin'in kitapla ilgili görüşlerini okudum. Kitap kapağıya, üzerindeki barkod ve piyano birleşimi logoyla ve arka kapağındaki görüşlerle kendini iyi pazarlamıştı. Kitabın birinci konusu da "Sağ Beynin Yükselişi" olunca kitabı almaya karar verdim.

İş dünyası büyük devrim yaşıyor. Asya etkisi, para bolluğu, globalleşme gibi etkenlerle artık oyunun kuralları çok değişti. Bu yeni düzene ayak uydurmak için artık yüksek seviyede bireyselleşme ve kişisel olarak işin yapılış ve işleyiş şekline etkide bulunmayı gerektiriyor. Artık üniversitede öğrenilenleri uygulayarak standart işleri yürütme devri sona eriyor. Hatta doktorluk, muhasebecilik, avulatlık gibi gözde meslekler bile yavaş yavaş teknoloji tehditi altına girmekte. Günümüzde birçok kimse basit sorunları için bilgi kaynağı olarak İnternet'ten faydalanıyor. Amerika da boşanma işlerini yürüten ve takip eden internet siteleri açıldı bile. İşlerinizi veya banka hesaplarınızı internetten takip edebileceğiniz teknolojilerden bahsetmeye bile gerek yok zaten her an iç içeyiz. Üretimde de benzer durum söz konusu. Bir mega markete gittiğinizde artık almak isteyeceğiniz üründen en az 10 çeşit bulabiliyorsunuz. Artık kıtlık döneminde değil bolluk döneminde yaşıyoruz. Her tür ihtiyaç için her tür ürün üretilmiş ve satışa hazır hale getirilmiş durumda. İş hayatının bu yeni koşulları eski köye yeni adet getiremeyen herkes açısından biraz sıkıntılı görünüyor. Değişen duruma adapte olamayanlar umudu sırlara, çekim güçlerine, kuantum fiziğine (!) bağlamış durumda.

Bu kitap hem bu yeni ortamı algılayabilmeniz hem de bu oyunun oyuncusu olabilmeniz için gerekli her tür bilgiyi alabileceğiniz güzel bir kaynak. Kitabın yazarı Daniel H. Pink. Yazar konuyu çok güzel bir dille ele almış. Belki de son dönemde okuduğum en iyi kitap diyebilirim. En güzeli lafı hiç uzatmadan kitabın içeridiği konulara biraz gözatalım.

Kitap iki ana kısımdan ve dokuz bölümden oluşuyor. Birinci kısım genelde bulunduğumuz ortamı anlayabilmemize yönelik konuları, ikinici kısım ise kendimizi hangi yönlerde geliştirmemiz gerektiğini anlatıyor.

1. Sağ beynin yükselişi
Kitap öncelikle bizi ve davranışlarımızı yöneten beynimizle ilgili bilmemiz gereken bazı önemli özellikleri açıklıyor. Burada verilen bilgiler kitabın devamında anlatılacak konularla için önemli.

2. Bolluk, Asya ve Otomasyon
Asya'nın ve Teknolojinin iş hayatını nasıl etkilediği ve neleri değiştirdiği bu bölümde anlatılıyor.

3. Yüksek Kavram, Yüksek Dokunuş
Bu bölüm kitabın ikinci kısmına geçiş niteliğinde. Sağ beynin ve kişisel özelliklerin iş yaşamındaki başarıyı nasıl etkilediği anlatılıyor.

4. Tasarım,
5. Öykü,
6. Senfoni,
7. Empati,
8. Oyun,
9. Anlam

Bu bölümler kitabın ikinci kısmını oluşturuyor. Her bir bölüm kendimizi nasıl geliştirebileceğimizle ilgili farklı bilgiler veriyor. Kitabın bu kısmı çok güzel tasarlanmış. Her bir bölüm konusunun neden önemli olduğuyla ilgili ilginç savlar içeriyor. Bölüm sonlarına ise portfölyo adı verilen kısımlar eklenmiş ve bu konuda gelişim sağlanabilmesi için neler yapılabileceği ile ilgili pratik fikirler veriliyor. Bu kısımlarda birçok internet adresi de mevcut. İnternet adresi haricinde bazı sosyal gruplar ve bazı kitaplar da öneriliyor. Sosyal gruplar genellikle Amerikalı okuyucuya hitap eder nitelikte ama birçoğuna internetten de erişim sağlanabiliyor. Önerilen kitaplardan arasında benim okuduklarım da var. Birçoğu önemli kitaplar.

Sonuç olarak bu kitabı ne tam olarak bir iş kitabı ne de bir kişisel gelişim kitabı olarak tanımlayabiliyorum. Bu gerçekten çok farklı ve hemen herkesin okuması gerektiğine inandığım bir kitap. Kitap adı felsefi anlamda biraz iddialı dursa da bir yönüyle adını hakettiğini düşünüyorum. Bunun değerlendirmesini kitap bittiğinde zaten kendiniz yapacaksınız.

Perşembe, Ekim 04, 2007

Regular Expressions Nedir?

Ne zamandır tatildi kitaptı derken programcılıkla ilgili konuları ihmal ettim. Bu yazımda her programcının ihtiyacı olabilecek Regular Expressions (Düzenli İfadeler) konusuna değineceğim. İnternette İngilizce veya Türkçe yazılmış birçok kaynak var ancak ben bu konuyu gerçekten çok zor anladım. Temel maksadım bir web sayfasındaki linkleri çeken bir program yazmaktı ancak işin temel mantığını çok geç kavradığım için bayağı bir uğraştım. Bu yazımda kendi anladığım şekilde çok basitten alarak işin temel mantığını vereceğim sonra işin detayları için güzel birkaç link vereceğim.

Regular Expressions aslında notepad gibi programlarda birşey aramak için kullandığımız mantığın daha kompleks bir şekli. Mesela bir yazı içerisinde "emre" kelimesini aramak için direk "emre" yazıyoruz. Bu zaten normal birşey. Ancak "e" ile başlayıp "e" ile biten 4 harfli herhangi birşey arıyorsak o zaman ifademizi "e..e" olarak veriyoruz. Burada "." işareti herhangi bir karakter anlamına geliyor. Eğer notepad programı regex ifadelerini destekleseydi arama kısmına "e..e" yazdığımızda yazı içerisinde emre, ezme gibi kelimeleri bulacaktı. Aynı şekilde "Cemre" kelimesinin de "emre" kısmını bulabilecekti. Bu noktada hemen bir kod örneği inceleyelim. Örneği C#'tan veriyorum.

public IList ExtractData(string regex, string icerik)
{
IList result = new List();
Match m;
Regex r = new Regex(regex, RegexOptions.IgnoreCase RegexOptions.Compiled);
for (m = r.Match(icerik); m.Success; m = m.NextMatch())
{
result.Add(m.Groups[0].Value);
}
return result;
}


Bu kod içerik içerisinde regex'e uyan bütün sonuçları liste olarak geri döndürecektir. Bir Regex nesnesi oluşturuyoruz ve Regex sınıfının Match metoduna içeriğimizi gönderiyoruz. Metod bize Match tipinde bir nesne döndürüyor. Bu Match nesnesi aramanın başarılı olup olmadığına dair bilgilerle birlikte neyin bulunduğunu da söylüyor. Regex'in gruplama özelliği olduğu için bunu bize Groups adında bir liste olarak veriyor ama grupları şimdilik kullanmayacağımız için biz sıfırıncı elemandan bulunan sonucu öğreniyoruz.

Normalde e ile başlayıp e ile biten kelimeler arayan programlar yazmayız. Güzel bir örnek bir web sayfası kaynağından linkleri ayıklayan bir kod yazmak olabilir. Html kodunda link href='http://www.xxx.com' şeklinde geçer yani amacımız tırnak içinde geçen linki ayıklamak. Bunu yapmak için href='[^']+' şeklinde bir ifade kullanacağız. İsterseniz bu ifadeyi detaylı olarak inceleyelim.

href=' yazarak aradığımız sonucun href=' ile başlaması gerektiğini belirttik. Devamındaki [] parantezi özel bir anlama geliyor. Köşeli parantez harf grupları oluşturmak için kullanılır. İlk örneğimizdeki e..e aramasını e..[ae] şeklinde yazarsak sonu a veya e ile biten herhangi bir harf grubunu seçmiş oluruz. Özetle bize dönecek sonuçlar şu özellikleri içerecek.

e ile başlayacak,
herhangi iki karakterle devam edecek,
sonra a veya e gelecek.

Aslında özel olarak belirtmezsek regex aramayı kelime kelime yapmaz. \b ifadesi boşluk anlamına gelir ve ifademizin başına ve sonuna \b koyarsak tam kelime araması yaparız. Bu durumda ifademizi \be..[ae]\b olarak yazmamız gerekir.

Eğer a,e ile biten kelimeleri değil de a,e ile bitmeyenleri seçmek istersek kümenin başına ^ işareti koyarız. \be..[^ae]\b ifadesi e ile başlayıp a,e den farklı herhangi bir karakterle biten 4 harfli kelimeleri bulur. emar, esin, erez gibi kelimeler başarılı olurken emre esma gibi kelimeler seçim dışında kalır. Küme içindeki ^ işareti kümenin tersi anlamına gelir.

href='[^']+' ifademize geri dönelim. href=' ile başladık ve [^'] ile devam ettik. Sondaki + ve ' işaretini şimdilik görmezden gelerek biraz daha araştırma yapalım. Eğer ifademizi sadece href='[^'] olarak yazarsak o zaman href=' ile başlayan ve sonraki karakteri ' haricinde herhangi birşey olan harf gruplarını seçeriz. Mesela bu ifadeyi

<a href='http://www.emreeren.com/'>Emre'nin sitesi</a> dizisinin içinde çalıştırırsak

<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

içeriğindeki kalın işaretli kısım döner. Yani sonuç olarak href='h elde ederiz. Aslında istediğimiz linkin tümünü seçmek. Burada da imdadımıza + işareti koşuyor. + işareti tekrarla anlamına gelir. [^']+ yazdığımızda sıradaki karakter ' harici olduğu sürece eşleştirmeye devam edilir. href='[^']+ dediğimizde regex yorumlayıcısı + işaretini görür ve ' işaretini görene kadar karakterleri okumaya devam eder. ' işaretini görünce de durur. Demek ki href='[^']+ ifadesi bize
href='http://www.emreeren.com sonucunu döndürür. Örneğimizin sonundaki ' işareti ise en sonraki ' işaretini de sonuca eklememize yarar yani href='[^']+' yazdığımızda dönecek sonucun sonuna ' işareti de eklenir. Bir daha özetle regex yorumlayıcısının adım adım ne yaptığına bakalım.

Kaynak:
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

Regex ifademiz:
href='[^']+'

Yorumlayıcı önce href=' kısmını bulur
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

sonra [^'] ifadesini görür ve sıradaki harfin ' işaretinden farklı olup olmadığına bakar. Tırnaktan farklı olduğu için sonuca h harfini de dahil eder.
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

sonra + işaretini görür ve bu işlemi ' hariç sıradaki her karakter için devam ettirir ve ' işaretine gelince durur.
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

sonra ' ifadesini görür ve sonraki ' işaretini de sonuca ekler.
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

Diyelim ki programımızı yazdık bitirdik. Bir de baktık ki başka bir web sayfası kaynağında
<a href="http://www.emreeren.com/"> örneğindeki gibi linklede ' yerine " kullanılmış. Bu durumda örnek kodumuz hiç bir sounç döndürmez çünkü yorumlayıcı ifademize uyan uygun karakter dizisi bulamaz. Bu sayfadan linkleri almak için ifademizi href="[^"]+" şeklinde yazmamız gerekirdi. Tamam ama link kapatmak için ' işareti mi yoksa " işareti mi kullanıldı nereden bileceğiz? Aslında sorumuzun cevabı yine yazımızın içinde var. Karakter kümelemeyi kullanarak iki alternatifi de ifademize ekleyeceğiz.

href=['"][^'"]+['"] (Biraz zor okunuyor ama "' kısmı " ve ' karakterlerinin yan yana yazılmış hali)

İfademizi yukarıdaki şekilde verdiğimizde href= eşlemesinden sonra ", ' karakterlerinden birine uyan, sonra ", ' karakterlerine uymayan bütün (+) karakterleri ve ", ' karakterlerinden birine uyan bir karakteri seçmiş oluyoruz. Bundan sonraki örnekleri basit okunması için kümelenmemiş halde vereceğim.

İşte şimdi can alıcı bir soruya sıra geldi. href='[^']+' ifadesini yazdığımızda linkler

href='http://www.emreeren.com'

şeklinde gelecek. Sonra biz baştaki href=' kısmını ve sonraki ' işaretini kaldırıp linki

http://www.emreeren.com

olarak düzenlemek zorunda kalacağız. Çünkü işimize yarayan bölüm burası. Sonuçların bu şekilde olması için gruplama özelliğini kullanmamız gerekiyor. İfademizde herhangi bir bölgeyi normal parantez içine aldığımızda o kısım bir grup olur. Yani ifademizi href='([^']+)' şeklinde yazarsak baştaki href=' ve sonraki ' işareti parantez dışında kaldığı için onlar grubun dışında kalır. Tabii gruplama kullandığımız için kodumuzda

m.Groups[0].Value yerine m.Groups[1].Value ifadesini kullanmamız gerekir. m.Groups listesinin birinci elemanı her zaman seçimin tümünü içerir. İfademizdeki gruplar da soldan 1,2,... diye numaralanarak listeye eklenir. Yani m.Groups[0].Value yine
href='http://www.emreeren.com' sonucunu döndürecektir ancak parantez içine aldığımız kısım yani http://www.emreeren.com kısmı m.Groups[1].Value sonucu olarak dönecektir.

Şimdi bütün bu öğrendiklerimizle
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a> içinden hem linkin adresini hem de açıklamasını çekelim ve bunları ayrı gruplarda gösterelim. Adım adım ifadeyi yazacağım ve seçimi kalın olarak göstereceğim

href='
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

href='[^']+'
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

href='[^']+'>
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

href='[^']+'[^<]+
<a href='http://www.emreeren.com/'>Emre'nin sitesi</a>

Emre'nin sitesi kısmını da seçimimize dahil ettikten sonra gruplamayı yapıyoruz.

href='([^']+)'([^<]+)

Bu sefer iki parantezimiz yani iki grubumuz var. Bu da demek oluyor ki

m.Groups[0].Value:
href='http://www.emreeren.com'>Emre'nin sitesi

m.Groups[1].Value:
http://www.emreeren.com

m.Groups[2].Value:
Emre'nin sitesi

sonuçlarını içerecektir.

Buraya kadar basit bir uygulamayı detaylı olarak anlatmaya ve olayın temel mantığını vermeye çalıştım. İtiraf etmek gerekirse gerçek hayat uygulamalarında çok daha farklı ve bol alternatif isteyen yapılar karşınıza çıkacak ama regular expressions olası her durum için işe yarayacak daha yığınla özelliğe sahip. Google tabiiki her zaman bir numaralı yardımcınız ama aşağıdaki linkleri de ziyaret edebilirsiniz.

http://www.regular-expressions.info (ingilizce)
...~meren/belgeler/regex/regex.html (Türkçe)

Ayrıca denemelerinizi yapabilmeniz için süper bir online test aracı da http://www.regextester.com/ adresinde.