February 14, 2013

Alıntı (acehreli:1356481900):

>

std.format'ın belgesinden ve birim testlerinden öğrendim. :)

> import std.array;
> import std.stdio;
> import std.format;
>
> void main()
> {
>     auto düzen = FormatSpec!char("Adım: %s\nSoyadım: %s");
>
>     string[] strl;
>     strl ~= "Zekeriya";
>     strl ~= "Durmuş";
>
>     auto yazıcı = appender!string;
>
>     foreach (değer; strl) {
>         düzen.writeUpToNextSpec(yazıcı);
>         formatValue(yazıcı, değer, düzen);
>     }
>
>     writeln(yazıcı.data);
> }
> ```

> Ali
>
Hocam bu std.format olanağı bana çok ilginç geldi. Tıpkı kendi gruplama düzen belirteçleri (<http://ddili.org/forum/thread/998>)mizi beliryebilmemiz gibi. Peki aşağıdaki olanağın bir benzerini, çağrışımsal diziler için de yapabilmek mümkün mü?

Ben beceremedim de...:(

import std.stdio;
struct Foo {
enum string[ubyte] data = [ 1: "bir", 2: "iki", 3: "üç" ];

string toString() @property {
auto outText = appender!string;
foreach(keys; data.keys) {
formattedWrite(outText, "%s: %s\n", keys, data[keys]);
}
return outText.data;
}
}
void main() {
Foo bar;
bar.writeln;
}/*
1: bir
2: iki
3: üç
*/



-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
February 14, 2013

Kusura bakmayın hocam, uzun açıklama yapmadan kodu pıtırdanak diye yazaraktan...:)

ve de

denemeden yayınladım. Oysa şu satır ile çalışıyormuş:

import std.stdio, std.format, std.array;

Gerçi sorduğum soruyu yapıdan çıkarıp main() içinde de yapabiliriz. Asıl sorduğuma gelince bu başlıkta konu edilen writeUpToNextSpec() ve formatValue() olanaklarını kullanabilir miyiz? Çünkü çağrışımsal dizilerle bunu bir türlü eşleştiremedim ve bende geleneksel yöntemle (tıpkı writeln ile yazar gibi) yaptım.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 14, 2013

Alıntı (Salih Dinçer):

>

Peki aşağıdaki olanağın bir benzerini, çağrışımsal diziler için de yapabilmek mümkün mü?

Bu soruyu anlamam çok zor oldu. Programın sonuna koyduğun açıklama satırlarını programın çıktısı sanmıştım. Değilmiş; senin istediğin çıktıymış. Oysa program segmentation fault ile sonlanıyormuş.

Eşleme tablolarıyla ilgili bir sıkıntı yüzünden öyle oluyor: hazır değerleri (literal) sorunlu. Çözüm, 'static immutable' olarak tanımlamak ve türün 'static this()'i içinde ilklemek: (Türlerin 'static this'leri olabildiğini bilmiyordum; öğrenmiş oldum. :))

import std.array;
import std.stdio;
import std.format;

struct Foo {
   static immutable string[ubyte] data;

   static this()
   {
       data = [ 1: "bir", 2: "iki", 3: "üç" ];
   }

 string toString() @property {
   auto outText = appender!string;
   foreach(keys; data.keys) {
     formattedWrite(outText, "%s: %s\n", keys, data[keys]);
   }
   return outText.data;
 }
}
void main() {
 Foo bar;
 bar.writeln;
}

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 15, 2013

Alıntı (acehreli):

>

...

Eşleme tablolarındaki elemanlar belirsiz sırada olduklarından onlarda writeUpToNextSpec() ve formatValue() kullanan bir yöntem herhalde mantıklı olmaz. Daha doğrusu, genel bir çözüm olmaz: Bazı programlar sıraya önem vermezken bazı programlar belirli bir sırada istiyor olabilirler.

...
Hocam çok güzel ifade etmişsin. Açıkçası FormatSpec yapısını anlayamadığım için bunun peşinden bir süre gittim. Aslında daha çok anlamaya gayret ettim. Gayretlerim sonuçsuz kalınca, bir cevap bulmak için bu konuyu devam ettirmeye karar verdim. Neticede çözüm olamayacağını da öğrenmiş olduk ama hala anlamaya çalışıyorum... :blush:

Peki hocam aşağıdaki grafiğe bakar mısın; yanlış anlamıyorum, değil mi?

Gerçi kodlarını incelemedim ve tahmin yürütüyorum ama data şu şekilde geziyor olmalı:

' : : : 'DATA' : : : ----> formatValue() -----v
____________ ^ __________
| 'FormatSpec' | !'char' ^ | 'appender' | !'string'
============ @writeUpToNextSpec ========== @data ---v
['SPEC']---^ v
('OUT')'

Yani 'FormatSpec' ile 'appender' adında iki yapımız var ve bunları haberleştiren' formatValue()' işlevimiz. 'Düzen', ilk başta yapı kurulurken veriliyor ama bunu 'writeUpToNextSpec()' ile veriyi biriktiren appender yapısına (yazıcı) eriştiriyoruz...

Allah Allah, bunu niye yapıyoruz?

Yani her iki işlev niye appender'a erişiyor, kafam almıyor...:)

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 15, 2013

Alıntı (Salih Dinçer):

>

' : : : 'DATA' : : : ----> formatValue() -----v
____________ ^ __________
| 'FormatSpec' | !'char' ^ | 'appender' | !'string'
============ @writeUpToNextSpec ========== @data ---v
['SPEC']---^ v
('OUT')'

Sanırım yavaş yavaş anlamaya başlıyorum. Kaynak kodlara baktım da 'writeUpToNextSpec()', aslında meslektaşı 'formatValue()''dan bağımsız çalışıyormuş. Daha açık bir ifade ile (adı üstünde up to next spec!) düzen ifadeleri üzerinde yürüyen bir işlevimiz, bir de bu düzene göre sonuç üretip appender'a yazan başka bir işlevimiz var...:)

Özetle, 'writeUpToNextSpec()' bağımsız çalışırken 'formatValue()' diğerine bağımlı sonuç üretiyor...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 14, 2013

Buradaki asıl soru, "%s" belirteçlerini bir dizideki elemanlarla sırayla eşleştirmekle ilgiliydi. Dizinin elemanları belirli bir sırada olduklarından ve düzen dizgisindeki "%s"ler belirli bir sırada durduklarında o eşleme mantıklı oluyor. Örneğin ad ve soyad "Adım: %s\nSoyadım: %s" dizgisine sırayla yerleştiriliyorlar.

Eşleme tablolarındaki elemanlar belirsiz sırada olduklarından onlarda writeUpToNextSpec() ve formatValue() kullanan bir yöntem herhalde mantıklı olmaz. Daha doğrusu, genel bir çözüm olmaz: Bazı programlar sıraya önem vermezken bazı programlar belirli bir sırada istiyor olabilirler.

Tabii, sıralı isteyen programların çeşitli çözümleri var: eşleme tablosu yerine ikili ağaç kullanmak veya eşleme tablosunun .keys() niteliğini önce sort() etmek ve onu sırayla ilerlemek.

Eşleme tabloları olsa olsa "%(" ve "%)" gruplama belirteçleri ile uygun kullanılabilirler gibi geliyor. Baktım, zaten destekleniyormuş! :) Önemli olan, tablo elemanları için iki tane %s kullanmakmış:

import std.stdio;

void main()
{
   auto data = [ 1: "bir", 2: "iki", 3: "üç" ];
   writefln("%-(%s:%s\n%)", data);
}

Çıktısı:
'1:bir
2:iki
3:üç
'
Yukarıdaki düzen dizgisi içindeki tire işareti string değerlerin çift tırnaklarını kaldırmaya yarıyor.

Konum belirteçleri de kullanılabiliyormuş:

import std.stdio;

void main()
{
   auto data = [ 1: "bir", 2: "iki", 3: "üç" ];
   writefln("%-('%2$s' değerini elde etmek için '%1$s' kullanınız%|\n%)",
            data);
}

Son eleman için de "kullanınız" yazdırılsın diye "%|" kullandım. Çıktısı:
''1' değerini elde etmek için 'bir' kullanınız
'2' değerini elde etmek için 'iki' kullanınız
'3' değerini elde etmek için 'üç' kullanınız
'

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 15, 2013

(Bunları en son yazdığını görmeden yazmışım.)

Bence olduğundan daha karmaşık düşünüyorsun. :) Şöyle daha basit olabilir mi:

FormatSpec üzerinde adım adım ilerleyebildiğimiz bir tür. Yukarıdaki dizgiyi kendi içinde üç parça haline getiriyor: "Merhaba ", "%s", ve "!". (Tabii, eğer kullanılmışsa her düzen belirtecinin kaç haneye yazılmasının istendiği, vs. gibi bilgileri de barındırıyor.)

Ayrıca bkz. /usr/include/d/dmd/phobos/std/format.d ('struct FormatSpec(Char)' diye başlayan yerde.)

  • 'formatValue': Kendisine verilen FormatSpec'in şu anda işaret etmekte olduğu düzen belirtecine yine kendisine verilen değeri uyguluyor. Sonuçta oluşturduğu karakterleri ilk parametresi olan OutputRange aralığını yazıyor. (Appender olması şart değil.)

  • 'writeUpToNextSpec' (Bu neden belgelenmemiş acaba?) Varsa, düzen belirtecinin başındaki düzen belirtecini atlıyor (çünkü "%s" diye bir şeyin yazılmasını istemeyiz) ve ondan sonraki düzen belirteci olmayan bütün karakterleri yazdırıyor. Yukarıdaki örneğe göre, eğer en başta çağırmışsak "Merhaba", en sonda çağırmışsak "!" yazdırır. Ek olarak, bir düzen dizgisi bulup bulmadığını da bildiriyor. Örneğin, "!" yazdırdıktan sonra bütün düzen dizgisi tükendiğinden 'false' döndürür.

  • 'Appender' Dizi sonuna eleman eklemeyi bilen ve söylendiğine göre bunu etkince yapan bir OutputRange. Buradaki tek görevi, çıkışa gönderilen karakterleri depolamak. Bunun yerine başka bir OutputRange de kullanılabilirdi.

Özetle, bir FormatSpec üzerinde "yazdır, bir sonrakine geç, yazdır, bir sonrakine geç" diye ilerliyoruz ve FormatSpec'i bize "bir şey kalmadı" diyene kadar tüketiyoruz.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 15, 2013

Ayrıntılı açıklamalar için teşekkür ederim...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 15, 2013

Alıntı (acehreli:1356546245):

>
>         enforce(belirteçVar_mı,
>                 format("Şu değer(ler) için belirteç bulunamadı:", strl[i..$]));
> ```

>

Test edilmeyen kod affetmez! Orada başından beri bir hata var. :) O hata mesajının içinde sonraki parametrelere karşılık %s bulunmuyor.

Biraz daha düşününce bunu daha temiz yazabileceğimizi de farkettim. writeUpToNextSpec() öcekinde üç kere çağrılıyordu; şimdi tek kere:

import std.array;
import std.stdio;
import std.format;
import std.exception;
import std.string;

void main()
{
auto düzen = FormatSpec!char("Adım: %s\nSoyadım:%s\nMerhaba");

string[] strl;
strl ~= "Zekeriya";
strl ~= "Durmuş";

auto yazıcı = appender!string;

while (düzen.writeUpToNextSpec(yazıcı)) {
enforce(!strl.empty, format("Fazladan düzen belirteci bulundu: %%%s%s ",
düzen.spec, düzen.trailing));

   formatValue(yazıcı, strl.front, düzen);
   strl.popFront();

}

enforce(strl.empty, format("Şu değer%s için belirteç bulunamadı: %(%s, %).",
strl.length == 1 ? "" : "ler", strl[]));

writeln(yazıcı.data);
}


Ama dikkat! Bu strl'yi tüketir. Ama bütün kod bir işlevin içindeyse sorun değildir çünkü o zaman işlevin parametresi tükenmiş olur. O yüzden şu çok daha iyi:

import std.array;
import std.stdio;
import std.format;
import std.exception;
import std.string;

void düzenle(string düzenDizgisi, string[] dizi, ref Appender!string yazıcı)
{
auto düzen = FormatSpec!char(düzenDizgisi);

while (düzen.writeUpToNextSpec(yazıcı)) {
enforce(!dizi.empty, format("Fazladan düzen belirteci bulundu: %%%s%s ",
düzen.spec, düzen.trailing));

   formatValue(yazıcı, dizi.front, düzen);
   dizi.popFront();

}

enforce(dizi.empty, format("Şu değer%s için belirteç bulunamadı: %(%s, %).",
dizi.length == 1 ? "" : "ler", dizi[]));
}

void main()
{
auto yazıcı = appender!string;
düzenle("Adım: %s\nSoyadım:%s\nMerhaba", [ "Zekeriya", "Durmuş" ], yazıcı);
writeln(yazıcı.data);
}


Program fazladan düzen belirteci bulursa nerede olduğunu da biraz olsun belirtiyor. Ama tam başarılı değil çünkü bizim düzen dizgisindeki '\n' gibi kodlar düzen.trailing içinde gerçek satır başına dönüşmüş durumda. Ama olsun yine de yeterince kullanışlı.

Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
February 16, 2013

Üstad eline sağlık, özellikle aşağıdaki enforce() çok leziz görünüyor... :-p

Alıntı (acehreli):

>
>  enforce(dizi.empty, format("Şu değer%s için belirteç bulunamadı: %(%s, %).",
>                                dizi.length == 1 ? "" : "ler", dizi[]));
> ```

>

Gerçi, diziye bir eleman daha eklediğimde bende çalışmadı. Herhalde DMD 2.059 kullandığım için olsa gerek çünkü, sanırım "gruplama düzen belirteçi (<http://ddili.org/forum/thread/998>)" sonradan dile eklendiği için böyle oldu. Şöyle bir böcük olduğuna delalet eden ve/veya düzeltilmeye çalışılan bir hata çıktısı aldım:

'std.format.FormatException@std/format.d(62): format error
----------------
/deneme(immutable(char)[] std.string.bug2479format(TypeInfo[], void*)+0x54) [0x43d0e0]
'

En iyisi mi artık yeni sürüme geçmeli. Hatanın kaynağını bulurken farkında olmadan kodu geleneksel hale getirmişim:

void düzenle(string düzenDizgisi, string[] dizi, ref Appender!string yazıcı) {
auto düzen = FormatSpec!char(düzenDizgisi);

while (!dizi.empty) {
if(!düzen.writeUpToNextSpec(yazıcı)) { // Belirteç kalmadıysa,
break; // döngüden çık...
}
formatValue(yazıcı, dizi.front, düzen);
dizi.popFront();
}
}


Tabi hiç hata iletisi vermemesi ve belirteçlerin devamındaki '\nMerhaba'yı yazmaması büyük bir eksiklik olabilir. Bunun üzerinde çalışıyorken; bu sefer bilinçli olarak çağrışımsal dizilere (eşleme tablosu, çevrim tahtası) yönlendim. Meğer yapmak istediğim çok leziz görünmese de böyle bir şeymiş:

import std.array;
import std.conv;
import std.stdio;
import std.format;

void düzenle(string düzenDizgisi, string[int] dizi, ref Appender!string yazıcı) {
foreach(key; dizi.keys) {
auto düzen = FormatSpec!char(düzenDizgisi);
string[] değerler = [ dizi[key], to!string(key), "" ];
// sondaki '\n' karakterini görebilmesi için ----^
foreach(değer; değerler) {
düzen.writeUpToNextSpec(yazıcı);
formatValue(yazıcı, değer, düzen);
}
}
}

void main() {
auto yazıcı = appender!string;
düzenle("Adı: %s\nNumarası: %s\n", [ 11: "Ali", 22: "Salih", 33: "Talha" ], yazıcı);
yazıcı.data.write;
}/*
Adı: Talha
Numarası: 33
Adı: Ali
Numarası: 11
Adı: Salih
Numarası: 22
*/


Evet, çok iğrenç...:)

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]