Dizgiler
"merhaba" gibi metin parçalarının dizgi olduklarını zaten öğrenmiş ve şimdiye kadarki kodlarda çok yerde kullanmıştık. Dizgileri anlamaya yarayan iki olanağı da bundan önceki derslerde gördük: diziler ve karakterler...
Dizgiler o iki olanağın bileşiminden başka bir şey değildir: elemanlarının türü karakter olan dizilere dizgi denir. Örneğin dchar[] bir dizgi türüdür. Ancak, karakterler dersinde gördüğümüz gibi, D'de üç değişik karakter türü olduğu için, üç değişik dizgi türünden ve bunların bazen şaşırtıcı olabilecek etkileşimlerinden söz etmek gerekir.
Boşluğa kadar okunur
Bu bölümdeki program örneklerinde de kullanacağımız için, önce girişten dizgi okumayı görelim. Dizgiler de diğer türler gibi okunurlar:
import std.stdio; import std.cstream; void main() { dchar[] isim; write("İsminiz nedir? "); din.readf(&isim); writeln("Çok memnun oldum ", isim, "!"); }
Yukarıdaki programı denerseniz, girişten yalnızca bir kelime okuduğunu görürsünüz. İsim ve soyad birlikte girilmiş bile olsa, yalnızca isim okunur. Bunun nedeni, giriş akımlarından okurken, boşlukların ayraç olarak kullanılmasıdır. Örneğin nasıl girişte "10 100" gibi bir bilgi bulunduğunda onları iki tamsayı gibi düşünebilirsek, girişte "merhaba dünya" gibi bir bilgi bulunduğunda da onları iki dizgi olarak düşünürüz. O yüzden isim ve soyad girildiğinde readf ilk okumayı aralarındaki boşluğa kadar yapar ve soyadını girişte bırakır.
İkinci kelime kaybolmaz ve bir sonraki okumada kullanılmak üzere girişte bekler. Bunu görmek için girişten art arda iki dizgi okuyabiliriz:
write("Adınız ve soyadınız? "); din.readf(&ad); din.readf(&soyad); writeln("Çok memnun oldum ", ad, " ", soyad, "!");
Tek tırnak değil, çift tırnak
Tek tırnak, karakter sabitlerinin etrafına koyulur; dizgi sabitleri için çift tırnak kullanmak gerekir: 'a' karakter değeridir, "a" tek karakterli bir dizgidir.
string, wstring, ve dstring değişmezdirler
D'de üç karakter türüne karşılık gelen üç farklı karakter dizisi türü vardır: char[], wchar[], ve dchar[].
Bu üç dizi türünün değişmez olanlarını göstermek için üç tane de takma isim vardır: string, wstring, ve dstring. Bu takma isimler kullanılarak tanımlanan değişkenler değişmezdirler. Bir örnek olarak, wchar[] değişkendir, wstring değişmezdir. (D'nin değişmezlik kavramını daha sonraki derslerde göreceğiz.)
Örneğin bir string'in baş harfini büyütmeye çalışan şu kodda bir derleme hatası vardır:
string değişmez = "merhaba"; değişmez[0] = 'M'; // Derleme hatası!
Buna bakarak, değiştirilmesi istenen dizgilerin dizi yazımıyla yazılabileceklerini düşünebiliriz. Sol tarafı dizi yazımıyla yazarsak:
char[] bir_dilim = "merhaba"; // Bu da derleme hatası!
O kod da derlenemez. Bunun iki nedeni vardır:
- "merhaba" gibi kodun içine hazır olarak yazılan dizgilerin türü
string'dir ve bu yüzden değişmezdirler - Türü
char[]olan sol taraf, sağ tarafın bir dilimidir
Bir önceki dersten hatırlayacağınız gibi, sol taraf sağ tarafı gösteren bir dilim olarak algılanır. char[] değişebilir ve string değişmez olduğu için burada bir uyumsuzluk vardır. Bu yüzden derleyici, değişebilen bir dilim ile değişmez bir diziye erişilmesine izin vermemektedir.
Bu durumda yapılması gereken, değişmez dizinin bir kopyasını almaktır. Bir önceki derste gördüğümüz .dup niteliğini kullanarak:
import std.stdio; void main() { char[] dizgi = "merhaba".dup; dizgi[0] = 'M'; writeln(dizgi); }
Merhaba
Benzer şekilde, örneğin string gereken yerde de char[] kullanılamaz. Değişebilen char[] türünü, değiştirilemeyen string türüne dönüştürmek için de .idup niteliğini kullanmak gerekir.
char[] ad_soyad = ad ~ soyad;
writeln(tolower(ad_soyad.idup));
Bu, aşağıda gösterilecek olan std.string modülünün string alan işlevlerini çağırırken karşınıza çıkacak.
string'in şaşırtıcı olabilen uzunluğu
Unicode karakterlerinin bazılarının birden fazla baytla gösterildiklerini ve Türkçe'ye has harflerin iki baytlık olduklarını görmüştük. Bu, bazen şaşırtıcı olabilir:
writeln("aĞ".length);
3
O kodun çıktısı 3'tür. Yani "aĞ" dizgisi 2 harf içeriyor olsa bile dizinin uzunluğu 3'tür. Bunun nedeni, "merhaba" şeklinde yazılan hazır dizgilerin elemanlarının türlerinin char olmasıdır.
Bunun görünür bir etkisi, iki baytlık bir harfi tek baytlık bir harfle değiştirmeye çalıştığımızda karşımıza çıkar:
char[] d = "aĞ".dup; writeln("Önce: ", d); d[1] = 't'; writeln("Sonra:", d);
Önce: aĞ
Sonra:at� ← YANLIŞ
O kodda dizginin 'Ğ' harfinin 't' harfi ile değiştirilmesi istenmiş, ancak 't' harfi tek bayttan oluştuğu için 'Ğ'yi oluşturan baytlardan ancak birincisinin yerine geçmiş ve ikinci bayt çıktıda belirsiz bir karaktere dönüşmüştür. Bu yüzden, belki de bazı başka dillerin normal karakter türü olan char'ı artık geride bırakmalı ve hep wchar veya dchar türlerini kullanmalıyız:
wchar[] d = "aĞ"w.dup; writeln("Önce: ", d); d[1] = 't'; writeln("Sonra:", d);
Önce: aĞ Sonra:at
Doğru çalışan kodda iki değişiklik yapıldığına dikkat edin:
- dizginin türü
wchar[]olarak belirlenmiştir - "aĞ"w hazır dizgisinin sonunda
wbelirteci kullanılmıştır; o belirtecin anlamı bir sonraki başlıkta açıklanıyor
Hazır dizgiler
Hazır dizgilerin özellikle belirli bir karakter türünden olmasını sağlamak için sonlarına belirleyici karakterler eklenir:
import std.stdio; void main() { string s = "aĞ"c; // bu, "aĞ" ile aynı şeydir wstring w = "aĞ"w; dstring d = "aĞ"d; writeln(s.length); writeln(w.length); writeln(d.length); }
3 2 2
a ve Ğ harflerinin her ikisi de wchar ve dchar türlerinden tek bir elemana sığabildikleri için, son iki dizginin uzunlukları 2 olmaktadır.
Dizgi birleştirmek
Dizgiler aslında dizi olduklarından, dizi işlemleri onlar için de geçerlidir. İki dizgiyi birleştirmek için ~ işleci ve bir dizginin sonuna başka bir dizgi eklemek için ~= işleci kullanılır:
import std.stdio; import std.cstream; void main() { dchar[] isim; write("İsminiz? "); din.readf(&isim); // Birleştirme örneği: dchar[] selam = "Merhaba " ~ isim; // Sonuna ekleme örneği: selam ~= "! Hoşgeldin..."; writeln(selam); }
İsminiz? Can Merhaba Can! Hoşgeldin...
Dizgileri karşılaştırmak
Not: Bu yazının yazıldığı dönemde henüz Phobos Türkçe'yi tam desteklemiyor. Aşağıdaki işlevleri kullanırken bu konuda sorunlarla karşılaşabilirsiniz. Bu aksaklıklar giderildiğinde bu not da buradan kalkmış olacak.
Daha önce sayıların küçüklük büyüklük karşılaştırmalarında kullanılan <, >=, vs. işleçleri görmüştük. Aynı işleçleri dizgilerle de kullanabiliriz. Bu işleçlerin küçüklük kavramı dizgilerde alfabetik sırada önce anlamındadır. Benzer şekilde, büyüklük de alfabetik sırada sonra demektir:
import std.stdio; import std.cstream; void main() { write("İki dizgi giriniz: "); dchar[] dizgi_1; dchar[] dizgi_2; din.readf(&dizgi_1, &dizgi_2); if (dizgi_1 == dizgi_2) { writeln("İkisi aynı!"); } else { dchar[] önce_olan; dchar[] sonra_olan; if (dizgi_1 < dizgi_2) { önce_olan = dizgi_1; sonra_olan = dizgi_2; } else { önce_olan = dizgi_2; sonra_olan = dizgi_1; } writeln("Sıralamada önce ", önce_olan, ", sonra ", sonra_olan, " gelir"); } }
Büyük küçük harfler farklıdır
Harflerin büyük ve küçük hallerinin ayrı karakter kodlarının olması onların birbirlerinden farklı oldukları gerçeğini de getirir. Örneğin 'A' ile 'a' farklı harflerdir.
Ek olarak, ASCII tablosundaki kodlarının bir yansıması olarak, büyük harflerin hepsi, sıralamada küçük harflerin hepsinden önce gelir. Örneğin büyük olduğu için 'B', sıralamada 'a'dan önce gelir. Aynı şekilde, "aT" dizgisi, 'T' harfi 'ç'den önce olduğu için "aç" dizgisinden önce sıralanır.
Bazen dizgileri harflerin küçük veya büyük olmalarına bakmaksızın karşılaştırmak isteriz. Böyle durumlarda yukarıda gösterilen aritmetik işleçler yerine, aşağıda gösterilecek olan icmp işlevini kullanmak gerekir.
std.string modülü
std.string modülü dizgilerle ilgili işlevler içerir. Bu işlevlerin tam listesini Ddili Wiki'nin std.string sayfasında bulabilirsiniz.
Oradaki işlevler içinden şunların hem kullanımı daha kolaydır, hem de daha sık karşılaşıldığını söyleyebiliriz. Belgelerinde bu işlevler için örnek programlar da bulacaksınız:
cmp: Aldığı iki parametreyi karşılaştırır ve birincisi ikincisinden alfabetik olarak önceyse eksi bir değer, sonraysa artı bir değer, eşitlerse 0 değerini döndürüricmp:cmp'a benzer şekilde çalışır. Farkı, dizgileri küçük büyük harf ayrımı gözetmeksizin karşılaştırmasıdırindexOf: Verilen karakteri bir dizgi içinde baştan sona doğru arar ve bulursa bulduğu yerin indeksini, bulamazsa -1 değerini döndürür. Seçime bağlı olarak bildirilebilen üçüncü parametre, küçük büyük harf ayrımı olmadan aranmasını sağlarlastIndexOf:indexOf'a benzer şekilde çalışır. Farkı, sondan başa doğru aramasıdırcount: Birinci dizgi içinde ikinci dizgiden kaç tane bulunduğunu sayartolower: Verilen dizginin, bütün harfleri küçük olan eşdeğerini döndürürtoupper:tolower'a benzer şekilde çalışır. Farkı, büyük harf kullanmasıdırsplit: Dizgiyi oluşturan kelimeleri içeren bir dizgi dizisi döndürürjoin:split'in tersi olarak çalışır; bir dizi içindeki kelimeleri, aralarına belirtilen ayraç gelecek şekilde birleştirirstrip: Dizginin başındaki ve sonundaki boşlukları silerreplace: Dizginin içindeki belirli bazı karakterleri başka karakterlerle değiştirirreplaceSlice: Dizginin bir dilimini başka dizgiyle değiştiririnsert: Dizginin içine başka dizgi yerleştirir
Problemler
- std.string modülünün belgesine hızlıca da olsa bir göz atın.
~işlecini de kullanan bir program yazın: kullanıcı, bütünüyle küçük harflerden oluşan ad ve soyad girsin; program önce bu iki kelimeyi aralarında boşluk olacak şekilde birleştirsin ve sonra baş harflerini büyütsün. Örneğin "ebru" ve "domates" girildiğinde programın çıktısı "Ebru Domates" olsun.- Kullanıcıdan bir kelime alın. Kelimenin içindeki ilk 'a' harfinden, kelimenin içindeki son 'a' harfine kadar olan bölümünü yazdırsın. Örneğin kullanıcı "balıkadam" dizgisini girdiğinde ekrana "alıkada" yazdırılsın.
Bu programda çalışırken toupper, capitalize, ve capwords işlevlerinin üçünü de deneyin ve farklılıklarını görün.
Bu programda indexOf ve lastIndexOf işlevlerini kullanarak iki değişik indeks bulmanız, ve bu indekslerle bir dilim oluşturmanız işe yarayabilir.
D.ershane
Forum
Wiki
Projeler
Tanıtım
İletişim
Hakları