Forum: Ders Arası RSS
std.string indexOf
erdem (Moderatör) #1
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: std.string indexOf
Wiki'nin std.string sayfasında bulunan örnek çalışma zamanı hatası veriyor:

import std.stdio;
import std.cstream;
import std.string;
 
 
void main()
{
    string dizgi = "Çay bahçesi";
 
    writeln ('"', dizgi, '"',
             " içinde hangi harfi arayayım? ");
 
    dchar harf;
    
    din.readf (&harf);
 
    int indeks = indexOf (dizgi, harf);
 
    if (indeks == -1) {
        writeln (harf, " harfi yok");
 
    } else {
        writeln ("Buldum! İndeksi ", indeks);
    }
                
}

$ ./deneme
"Çay bahçesi" içinde hangi harfi arayayım?
a
Segmentation fault

wstring ya da dstring kullansak da sonuç değişmiyor. Gene bu giriş akımının Enter tuşunu karakter olarak algılamasıyla alakalı olabilir mi acaba?
erdem (Moderatör) #2
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Gene bu konuyla alakalı olarak wikideki bir başka örnek:

import std.stdio;
import std.cstream;
import std.string;
 
void main()
{
    string [] kelimeler;
 
    kelimeler.length = 3;
    kelimeler [0] = "Boğaz";
    kelimeler [1] = "Köprüsü";
    kelimeler [3] = "Gişeleri";
 
    string birleşimleri = join (kelimeler, " ");
    
    writeln (birleşimleri);
    
}

Sanırım bu da 1 baytlık string üzerinde 2 baytlık karakterler kullanınca hata veriyor.

$ ./deneme
core.exception.RangeError@deneme(14): Range violation
./deneme(onRangeError+0x28) [0x80b3a68]
./deneme(_d_array_bounds+0x16) [0x80a5cb6]
./deneme(_D6deneme7__arrayZ+0x12) [0x80a2f8e]
./deneme(_Dmain+0x83) [0x80a2267]
./deneme(_D2rt6dmain24mainUiPPaZi7runMainMFZv+0x1a) [0x80a5e16]
./deneme(_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv+0x20) [0x80a5da8]
./deneme(_D2rt6dmain24mainUiPPaZi6runAllMFZv+0x32) [0x80a5e5a]
./deneme(_D2rt6dmain24mainUiPPaZi7tryExecMFMDFZvZv+0x20) [0x80a5da8]
./deneme(main+0x94) [0x80a5d54]
/lib/libc.so.6(__libc_start_main+0xe6) [0xc49bc6]
./deneme() [0x80a2131]

acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konuyu çok güzel bir zamanda açmışsın. :) Lütfen sabırla okuyunuz. Bu çok belalı bir konu. :/

Ben şu sıralarda D.ershane'deki bütün std.cstream'li örnekleri çıkartmakla meşgulüm. Şu anda Dizgiler dersini bitirmek üzereyim. O işi yaparken derslerin bazı yerlerini hem düzeltiyorum hem de yeni paragraflar ekliyorum.

1) Gösterdiğin program dmd'nin veya Phobos'un bir hatasını sergiliyor. std.cstream, din, ve dout kullanan programlar için artık kafa yormamayı öneriyorum. İzninle onları bir kenara bırakalım.

2) Girişten dchar okumak, şu kadar kolay olmalı:

    dchar c;
    readf(" %s", &c);

Ne yazık ki ilginç bir hata var: Giriş UTF-8 olduğunda örneğin ö'nün iki baytla temsil edildiğini biliyoruz. readf, o iki bayttan yalnızca ilkini okuyor, dchar'ın değeri yapıyor, ve dchar bambaşka bir karakteri temsil etmeye başlıyor.

Bununla ilgili bir hatayı daha dün açtım:

  http://d.puremagic.com/issues/show_bug.cgi?id=5743

Yani "kod birimi" (code unit) okuyup onu "kod noktası" (code point) olarak kullanıyorlar.

(Not: Standart girişi tek kullananlar biziz galiba. İki seneye yakın D ile ilgileniyorum henüz giriş ve çıkışın tam doğru çalıştıklarını görmedim.)

3) O hata nedeniyle şimdilik wchar veya dchar okuyamıyoruz. Zaten char okumak tamamen yanlış olur çünkü işimiz kod birimleri ile değil.

O yüzden bugün için satır okumaktan ve ilk karakterini kullanmaktan başka çaremiz yok. (Başka yöntemler de vardır ama bence bu yeterli.) Satır okuma ile de bir soru sormuş ve şu yanıtları almıştım:

  http://www.digitalmars.com/webnews/newsgroups.…?art_grou…

O konudan anlaşıldığına göre, satır okunduğunda da satırın sonunda basılan Enter'ın kodu da girişte beliriyor. Eğer onu istemiyorsak satır sonundaki kodlardan kurtulmak için chomp'u, dizginin her iki ucundaki bütün boşluklardan kurtulmak için de strip'i kullanabiliriz. Bu programda boşluk karakteri de yasal olduğu için ben chomp'u kullanacağım.

import std.stdio;
import std.string;
 
void main()
{
    string dizgi = "Çay bahçesi";
 
    writeln ('"', dizgi, '"',
             " içinde hangi harfi arayayım? ");
 
    string harf = chomp(readln());
 
    /*
     * Burada hata aldım:
     *
     *     int indeks = indexOf (dizgi, harf);
     *
     *   Error: cannot implicitly convert expression
     *   (indexOf(dizgi,harf,cast(CaseSensitive)1)) of type
     *   long to int
     *
     * Hangi sürümü kullanıyorsun? Benimki 2.052
     *
     * auto veya long ile düzeliyor:
     */
    auto indeks = indexOf (dizgi, harf);
 
    if (indeks == -1) {
        writeln (harf, " harfi yok");
 
    } else {
        writeln ("Buldum! İndeksi ", indeks);
    }
}

Ama iki sorun var:

i) harf aslında bir dizgi. Eğer onu tek harfle kısıtlamak istiyorsan uzunluğunun 1 olduğunu denetleyebilirsin. Ama string'in uzunluğu harfine göre değişik olur. ö için 2, a için 1... O yüzden okuduğumuz türün dstring olması gerekiyor:

    dstring harf = chomp(readln());

Derlenmez! Çünkü chomp'ün döndürdüğü tür string. İki çözüm var:

a) readln'e dstring okumasını söylemek. readln, ne türde okuyacağını bir şablon parametresi olarak alır. Deneyelim:

    dstring harf = chomp(readln!dstring());

Derlenmez! Çünkü iki farklı readln var: stdin'in üye işlevi olan ve serbest işlev olan. Ben yukarıda serbest işlevi kullanıyorum ve ne yazık ki o "şu türden olsun" olanağını sunmuyor. Peki, stdin'in üye işlevini çağıralım:

    dstring harf = chomp(stdin.readln!dstring());

b) Bence daha temizi, chomp'un döndürdüğü string'i dstring'e std.conv.dtext ile dönüştürmektir:

import std.conv;
// ...
    dstring harf = dtext(chomp(readln()));

Güzel... Şimdi artık dstring olarak okuduğumuz harf'in gerçekten tek harf olduğunu denetleyebiliriz. ö de olsa a da olsa dchar bütün Unicode karakterlerini taşıyabilir. Bu gibi denetlemeler için std.exception.enforce kullanılır.

Bugüne kadar hep assert kullandık ama kullanıcı ile ilgili konularda enforce doğru. Çok çok kısa olarak:

- assert, programcının kendisini denetlemesi ile ilgili. Error atar ve Error'ın yakalanması önerilmez.

- enforce, işlevlerin aldığı giriş değerleri gibi başka durumlarla ilgili. Exception atar; Exception yakalanabilir ve gerekirse durum kurtarılabilir

(O konuya daha fazla girmek istemiyorum. Parmaklarım ağrıdı ve daha girişten dizgi (aslında harf) okuyamadık. :p)

import std.exception;
// ...
    dstring harf = dtext(chomp(readln()));
    enforce(harf.length == 1, "Tek harf olmalı");

Daha bitmedi...

string ve wstring "harf" kavramını ifade etmeye uygun değiller. O yüzden programın bu haline a harfi verildiğinde çıktısı şöyle oluyor:

"Çay bahçesi" içinde hangi harfi arayayım? 
a
Buldum! İndeksi 2

Eğer a'nın 1 indeksinde bulunmasını istiyorsak asıl dizgiyi de dstring seçmemiz gerekir.

İşte doğru çalışan program:

import std.stdio;
import std.string;
import std.conv;
import std.exception;
 
void main()
{
    dstring dizgi = "Çay bahçesi";
 
    writeln ('"', dizgi, '"',
             " içinde hangi harfi arayayım? ");
 
    dstring harf = dtext(chomp(readln()));
    enforce(harf.length == 1, "Tek harf olmalı");
 
    auto indeks = indexOf (dizgi, harf);
 
    if (indeks == -1) {
        writeln (harf, " harfi yok");
 
    } else {
        writeln ("Buldum! İndeksi ", indeks);
    }
}

Tabii açtığım hata giderildiğinde tek harf okumak çok daha kolay olacak.

Bu konuları D.ershane'ye de eklemeye başlamıştım. Yazdığım taslakları size de göstereceğim. Bakalım size mantıklı gelecek mi...

Ali
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #2
Neyse ki onun çözümü çok basit! :)

erdem:
    kelimeler.length = 3;
    kelimeler [0] = "Boğaz";
    kelimeler [1] = "Köprüsü";
    kelimeler [3] = "Gişeleri";

3 yasal bir indeks değil.

Ayrıca şöyle yazılsa daha basit herhalde:

    string[] kelimeler = [ "Boğaz", "Köprüsü", "Gişeleri" ];

Ama her durumda o kadar basit yazılamaz.

Ali
erdem (Moderatör) #5
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #3
acehreli:
2) Girişten dchar okumak, şu kadar kolay olmalı:

    dchar c;
    readf(" %s", &c);

Ne yazık ki ilginç bir hata var: Giriş UTF-8 olduğunda örneğin ö'nün iki baytla temsil edildiğini biliyoruz. readf, o iki bayttan yalnızca ilkini okuyor, dchar'ın değeri yapıyor, ve dchar bambaşka bir karakteri temsil etmeye başlıyor.

Bununla ilgili bir hatayı daha dün açtım:

  http://d.puremagic.com/issues/show_bug.cgi?id=5743

Hımm. Bu hatayı ilk kez görüyorum.

acehreli:
import std.stdio;
import std.string;
 
void main()
{
    string dizgi = "Çay bahçesi";
 
    writeln ('"', dizgi, '"',
             " içinde hangi harfi arayayım? ");
 
    string harf = chomp(readln());
 
    /*
     * Burada hata aldım:
     *
     *     int indeks = indexOf (dizgi, harf);
     *
     *   Error: cannot implicitly convert expression
     *   (indexOf(dizgi,harf,cast(CaseSensitive)1)) of type
     *   long to int
     *
     * Hangi sürümü kullanıyorsun? Benimki 2.052
     *
     * auto veya long ile düzeliyor:
     */
    auto indeks = indexOf (dizgi, harf);

Aslında ben de dmd v2.052 sürümünü kullanıyorum. Ben direkt dmd program.d diye basitçe derliyorum.

acehreli:
b) Bence daha temizi, chomp'un döndürdüğü string'i dstring'e std.conv.dtext ile dönüştürmektir:

import std.conv;
// ...
    dstring harf = dtext(chomp(readln()));

Bence de hem daha temiz hem basit :)

Dilin nasıl tasarlandığını ve işin teknik tarafını bilmiyorum ama aslında wstring ya da dstring'in string sınıfına benzer yöntemleri olsa ve örneğin indexOf parametre olarak kendisine bir wstring ya da dstring geçilse bile bir tamsayı döndürse daha mantıklı olmaz mı..

Ben ilk planda D'nin C++'nin karmaşıklığını azaltacağını düşünüyordum ama böyle giderse sanki daha karışık bir yazım biçimi olacak :) O yüzden Basic, Lua gibi dillerin neden popüler olduğunu anlıyorum.
Bu mesaj erdem tarafından değiştirildi; zaman: 2011-03-18, 02:20.
erdem (Moderatör) #6
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #4
acehreli:
Neyse ki onun çözümü çok basit! :)

erdem:
    kelimeler.length = 3;
    kelimeler [0] = "Boğaz";
    kelimeler [1] = "Köprüsü";
    kelimeler [3] = "Gişeleri";

3 yasal bir indeks değil.

Evet. Bu basit hatayı görmemişim.

Programın kodlarını karakter karakter kopyalama huyumdan vazgeçsem çok iyi olacak galiba :)
acehreli (Moderatör) #7
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #5
erdem:
acehreli:
import std.stdio;
    /*
     * Burada hata aldım:
     *
     *     int indeks = indexOf (dizgi, harf);
     *
     *   Error: cannot implicitly convert expression
     *   (indexOf(dizgi,harf,cast(CaseSensitive)1)) of type
     *   long to int
     *
     * Hangi sürümü kullanıyorsun? Benimki 2.052
     *
     * auto veya long ile düzeliyor:
     */
    auto indeks = indexOf (dizgi, harf);

Aslında ben de dmd v2.052 sürümünü kullanıyorum. Ben direkt dmd program.d diye basitçe derliyorum.

Anlaşıldı: Ben -m64 seçeneği ile derliyormuşum. indexOf() sizediff_t diye bir tür döndürüyor. O tür de aslında 32 veya 64 olma durumuna göre ya int'in ya da long'un takma ismi oluyor.

auto yerine sizediff_t yazsak da oluyor yani.

Ben ilk planda D'nin C++'nin karmaşıklığını azaltacağını düşünüyordum ama böyle giderse sanki daha karışık bir yazım biçimi olacak :) O yüzden Basic, Lua gibi dillerin neden popüler olduğunu anlıyorum.

Katılıyorum. Karmaşıklığın bir bölümü işin doğasından geliyor: C gibi olabildiğince hızlı olmaları gerekiyor; yoksa "sistem dili" olarak kabul edilemez. Bir yandan da çok yararlı üst düzey kavramları destekliyorlar.

Örneğin Unicode çok karmaşık. D de o yüzden birleştirici kod noktası kavramına kadar desteklemiş ve gerisine karışmamış. O kısıtlama aslında biraz tesadüfi olmuş; çünkü g ve  ̆ şapkasının bileşiminin ğ'ye eşit olma kavramından baş D'cilerin haberi yokmuş. :D Öte yandan, programcılık açısından belki de ğ'nin g ve  ̆ şapkasına eşit olmasını istemiyor da olabiliriz.

Ne yapalım... :-/ Bence diğer dilleri de bilelim ve bilerek kullanalım.

Ali
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Forum: Ders Arası RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-21, 15:18:57 (UTC -08:00)