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.
-
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.
-
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.)
- 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.php?art_group=digitalmars.D.learn&article_id=25635
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
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]