D.ershane D Programlama Dili Dersleri

akım: [stream], nesnelerin art arda erişildiği giriş çıkış birimi
değişmez: [immutable], programın çalışması süresince kesinlikle değişmeyen
dilim: [slice], başka bir dizinin bir bölümüne erişim sağlayan yapı
dizgi: [string], "merhaba" gibi bir karakter dizisi
dizi: [array], elemanları yan yana duran ve indeksle erişilen topluluk
işlev: [function], programdaki bir kaç adımı bir araya getiren program parçası
karakter: [character], 'a', '€', '\n', gibi en alt düzey metin parçası
Phobos: [Phobos], D dilinin standart kütüphanesi
takma isim: [alias], türün başka bir ismi
... bütün sözlük

Bölümler
İngilizce Kaynaklar
Diğer



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:

  1. "merhaba" gibi kodun içine hazır olarak yazılan dizgilerin türü string'dir ve bu yüzden değişmezdirler
  2. 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:

  1. dizginin türü wchar[] olarak belirlenmiştir
  2. "aĞ"w hazır dizgisinin sonunda w belirteci 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:

Problemler
  1. std.string modülünün belgesine hızlıca da olsa bir göz atın.
  2. ~ 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.
  3. Bu programda çalışırken toupper, capitalize, ve capwords işlevlerinin üçünü de deneyin ve farklılıklarını görün.

  4. 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.
  5. 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.

... çözümler