Forum: Ders Arası RSS
Belirli bir dosya formatıyla biçimlendirilmiş dosyayı okumak
Sayfa:  önceki  1  2 
acehreli (Moderatör) #16
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 ID 3933
Ben de regex'in kullanışsız olacağını düşünüyorum. Yukarıdaki bir kod şu diziyi yanlış ayrıştırıyor:

    auto dizi ="<b>matematiğe <b>benzer</b></b>";

Bu sorunun asıl amacından uzaklaştığımızı farkettim. Aslında amaç metin dosyasını okumak.

Kadir Can'ın yöntemi doğru gibi. Tek fark, belirlediğimiz etiketlere karşılık özel bir nesne oluşturacağız. Bir de bu işi özyinelemeli olarak yapacağız.

Zaman bulunca daha çok yazacağım. Ama daha önce de söylediğim gibi, farklı ortamlara yazdırma işine de baktığımızda "double dispatch"le karşılaşacağız. "double", çünkü hem metin bir kalıtım sıradüzenine ait, hem de gösterici. Temiz çözümü olmayabilir. C++'ta bazen "visitor pattern" kullanılır. D'de daha iyi yöntemler olabilir.

Ali
erdem (Moderatör) #17
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
regex yerine özyinelemeli yöntemle bir kısmını tekrar yazdım. Ama hala içiçe elemanları yazdıramıyor.
import std.string, std.stdio, std.conv;
 
void main() 
{   
    string[] elemanlar;
 
    auto yazı = "Çorba yaparken <b>matematiğe </b><b>benzer çok şeyler </b> olduğunu"
    "biliyoruz<u>ama bunların<u> nasıl kullanılacağı</u></u>";
 
başlangıç:
 
    // ilk < karakterini ara konumunu kaydet
    auto ilk = yazı.indexOf('<');
    
    // ikinci < karakterini ara konumunu kaydet
    auto ikinci = yazı[ilk + 1 .. $].indexOf('<') + ilk + 1;
 
    if (ilk > 0) {  // sadece metin var
        auto metin = yazı[0 .. ilk];
        elemanlar ~= metin;
        yazı = yazı[ilk .. $];
        if (yazı.length <= 0) goto çıkış;
        goto başlangıç;
        
    }
        
    if (yazı[ikinci + 1] == '/') {      // tek bir html elemanı var     
        //                           < >] 
        auto eleman = yazı[ilk .. ikinci + 4];
        yazı = yazı[ikinci + 4 .. $];
        if (yazı.length <= 0) goto çıkış;
        goto başlangıç;
 
    } else {
        writeln ("içiçe geçmiş etiketler var bu kısım henüz hazır değil");
        writeln ("dizinin son hali: ", yazı);
        
    }
 
çıkış:
    writeln("çıkıyorum");
}
double dispatch konusuyla ilgili burada bazı şeyler okudum.

http://c2.com/cgi/wiki?DoubleDispatch

Ama gerçekleştirme ayrıntılarını ben de merak ediyorum.
acehreli (Moderatör) #18
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ı
Yazdığın kodları okuyor muyuz diye denemek için mi goto kullandın! :-p

Ben gerçekten buna bakacak zaman bulamıyorum ama ilginç bir tesadüf, yakın zaman önce okuduğum Overload'da sanal işlev ve şablonların karışık kullanımını içeren bir çözüm görmüştüm.

ACCU Overload'ları ücretsiz olarak da veriyor. Yazı şu:

  http://accu.org/index.php/journals/1716

Belki bir fikir verir. (Bir kere daha okuyunca bana fikir verecek ama sonra okuyacağım. :))

Ali
erdem (Moderatör) #19
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
Yazdığın kodları okuyor muyuz diye denemek için mi goto kullandın! :-p
Aslında C++'de zaten böyle bir olanak yoktu sanırım. Hatta goto kullanmak ayıp bile karşılanıyordu :)

Ama D için böyle bir olanak olduğuna göre kullanayım diye düşündüm.
acehreli (Moderatör) #20
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ı
goto ezelden beri sorun oluşturmuştur. Aşağıdaki bağlantıdan bir alıntı:

D'de goto'yu kullanmak için hiçbir neden yoktur.

İç içe döngülerden veya switch deyimlerinden hangisinin etkileneceğini belirtmek için break ve continue deyimlerinde etiket belirtilebilir.

  http://ddili.org/ders/d/etiketler.html

Ali
erdem (Moderatör) #21
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
goto ifadelerini attıktan sonra bu şekilde olmuş oldu:
import std.string, std.stdio, std.conv;
 
string[] elemanlar;
    
void main() 
{
    auto yazı = "Çorba yaparken <b>matematiğe </b><b>benzer çok şeyler </b> olduğunu"
    "biliyoruz<u>ama bunların<u> nasıl kullanılacağı</u></u>";
    parçala(yazı);
    
}
 
void parçala(string yazı) {
    if (yazı.length > 0) {
        
        // ilk < karakterini ara konumunu kaydet
        auto ilk = yazı.indexOf('<');
    
        // ikinci < karakterini ara konumunu kaydet
        auto ikinci = yazı[ilk + 1 .. $].indexOf('<') + ilk + 1;
 
        if (ilk > 0) {  // sadece metin var
            auto metin = yazı[0 .. ilk];
            elemanlar ~= metin;
            yazı = yazı[ilk .. $];
            parçala(yazı);
        
        } else if (yazı[ikinci + 1] == '/') {      // tek bir html elemanı var
            auto eleman = yazı[ilk .. ikinci + 4];
            yazı = yazı[ikinci + 4 .. $];
            parçala(yazı);
        
        } else {
            writeln ("içiçe geçmiş etiketler var bu kısım henüz hazır değil");
            writeln ("dizinin son hali: ", yazı);        
        }
    }
}
Aslında goto 'lar biraz nostaljik oluyordu.

Bill amca.. Basic.. Bir de hiç modelini bile bilmediğim bir bilgisayarda Commodore'dan da önceydi galiba böyle goto kullanan bir program yazmaya çalıştığımı hatırlıyorum! :D
acehreli (Moderatör) #22
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ı
erdem:
bir bilgisayarda Commodore'dan da önceydi galiba böyle

Dikkat! Yaşın belli oluyor. :-p

Ben Sinclair Spectrum'cuydum.

Ali
erdem (Moderatör) #23
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
acehreli:
erdem:
bir bilgisayarda Commodore'dan da önceydi galiba böyle

Dikkat! Yaşın belli oluyor. :-p
Evet yaşlanıyoruz artık :) Hımm. Düşündüm de bu Commodore'lardan epey sonraymış. 90'lı yıllarda. Üzerinde windows ya da linux yoktu ama bir satranç programı ve müzik düzenleme yazılımı olduğunu hatırlıyorum.

Ama Commodore'ları da çok iyi hatırlıyorum. Commodore sanki tamamen oyun içindi. Sonra Amiga'larla da ne yaptığını anlamasak da bir bilgisayar dergisinde verilen program kodlarını yazıp çalıştırdığımızı hatırlıyorum. Bir de böyle editör, hata yakalayıcı falan da yoktu galiba. Bir sayfa kodu yazıp sonra hata olduğunda harf harf karşılaştırıp tekrar düzeltiyorduk.
erdem (Moderatör) #24
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Tamamen test edemedim ancak son hali bu şekilde oldu. Artık html elemanlarını da ekleyebiliyor.
import std.string, std.stdio, std.conv;
 
string[] elemanlar;
XmlElement[] elements;
bool alteleman;
 
 
class XmlElement 
{
    // ...
}
 
void parçala(string yazı) {
    if (yazı.length > 0) {        
        // ilk < karakterini ara konumunu kaydet
        auto ilk = yazı.indexOf('<');
        
        // ikinci < karakterini ara konumunu kaydet
        auto ikinci = yazı[ilk + 1 .. $].indexOf('<') + ilk + 1;
        if (ikinci != 0) {
            
            if (ilk > 0) {  // sadece metin var
                auto metin = yazı[0 .. ilk];
                elemanlar ~= metin;
                yazı = yazı[ilk .. $];
                alteleman = false;
                parçala(yazı);
        
            } else if (yazı[ikinci + 1] == '/') {      // tek bir html elemanı var
                auto içerik = yazı[ilk + 3 .. ikinci];
                auto etiket = yazı[ilk + 1 .. 2];
            
                if (alteleman) {
                    assert(elements.length > 0);
                    auto gecici = new XmlElement(etiket, içerik);
                    elements[elements.length - 1].addElement(gecici);
                } else {
                    elements ~= new XmlElement(etiket, içerik);
                }    
                    
 
                if (elements.length > 0) {
                    auto kaçtane = elements.length;
                    auto son = kaçtane - 1;
                }
                
                yazı = yazı[ikinci + 4 .. $];
                alteleman = false;
                parçala(yazı);
        
            } else {
                auto içerik = yazı[3 .. ikinci];
                auto etiket = yazı[ilk + 1 .. 2];
 
                if (alteleman == false) {
                    elements ~= new XmlElement(etiket, içerik);
                    alteleman = true;
 
                } else {
                    assert(elements.length > 0);
                    auto gecici = new XmlElement(etiket, içerik);
                    elements[elements.length - 1].addElement(gecici);
                }
 
                auto kaçtane = elements.length;
                auto son = kaçtane - 1;
                yazı = yazı[ikinci .. $];
                parçala(yazı);
            
            }
        }
    }
}
 
 
void main() 
{
    int etiketsayısı = 0;
    
    string[] elemanlar;
 
    auto yazı ="Deneme yaparken <b>matematiğe </b>benzer çok şeyler <b>olduğunu" 
               "biliyoruz<b> ama bunların nasıl kullanılacağı</b></b>";
    parçala(yazı);
 
    writeln("kaç tane: ", elements.length);
    
    for (int i = 0; i < elements.length; ++i) {
        writeln(elements[i]);
    }
    
}

İçiçe geçmiş html ifadelerini doğru bir şekilde ayrıştıramadığını farkettim. Aslında Ayrıştırıcı isimli bir sınıf mı yazsak. Örneğin kendisine geçilen:
<a>deneme<b>deneme<c>deneme</c>deneme</b>deneme</a>
Şeklindeki bir ifadeyi kendiliğinden ayrıştırabilse.
Bu mesaj erdem tarafından değiştirildi; zaman: 2011-05-06, 07:41.
Değişiklik nedeni: ek
erdem (Moderatör) #25
Ü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 ID 3917
erdem on 2011-05-03, 07:07:
Benim aklıma şu tür bir çözüm geldi. Bir Yazıcı nesnemiz olur <b> etiketine rastladığı zaman özellikler koyu yazmayı aç ya da </h> etiketine geldiği zaman özellikler gizli yazmayı kapat diyebilir.
Sorunun çözüm yöntemini baştan sona değiştirdim ve ilk aklıma gelen yöntemle yapmaya çalıştım.
import std.stdio, std.string;
 
struct Metin
{
    string yazı_;
    static bool koyu_;
    bool büyük_;
    bool köşeli_;
    bool gizli_;   
    
    this(string yazı) 
    {
        if (!koyu_ && !gizli_ && !köşeli_ && !büyük_) 
            yazı_ ~= yazı;
 
        else if (koyu_) {
            foreach (dchar harf; yazı) {
                writeln(harf);
                yazı_ ~= harf;
                yazı_ ~= harf;          
                
            }
        }   
        
    }
}
 
Metin[] elemanlar;
 
 
void çıkış(string mesaj) 
{
    writeln(mesaj);
}
 
void ayrıştır (string yazı) 
{
    // dizi içeriğini karakter karakter yaz
    for (int i = 0; i != yazı.length; ++i) {
        writeln(i, " ", yazı[i], " ");
    }
 
    if (yazı.length <= 0) çıkış("dizinin işlenmesi tamamlandı");
 
    // ilk < karakterini bul
    auto ilk = yazı.indexOf('<');
    writeln("ilk karakter: ", ilk);
 
    // yazının başında sadece metin var
    if (ilk > 0) {
        // metin kısmı ekle
        elemanlar ~= Metin(yazı[0 .. ilk]);
        // eklenen kısmı yazıdan çıkart
        yazı = yazı[ilk .. $];
        // son durumu göster
        writeln("yazının son hali: ", yazı);
        // tekrar başa dön
        ayrıştır(yazı);
 
    } else if (ilk == 0) {
        // en başta bir etiket var mı
        switch (yazı[0 .. 3]) {
        case "<b>": 
        {
            elemanlar[elemanlar.length - 1].koyu_ = true;
            // yazının en başını kısalt
            yazı = yazı[3 .. $];
            writeln("Yazının son hali", yazı);
            writeln("koyu yaptım");
            ayrıştır(yazı);
            break;
        }
        
        default:
            çıkış("Programda bir hata oluştu");
            
            break;
            
        }   
    }  
}
 
void main() 
{
    auto yazı = "Deneme yaparken<b>matematiğe</b>";
    ayrıştır(yazı);
 
    writeln(elemanlar[0].yazı_);
    writeln(elemanlar[1].yazı_);
    
}
Yalnız gördüğüm bir eksik metin yapısına niteliklerin açılma sırasını da eklemeliyiz galiba. Örneğin 0:Koyu 1:Köşeli ya da 0:Büyük 1:Gizli gibi..
Bu mesaj erdem tarafından değiştirildi; zaman: 2011-05-07, 07:56.
erdem (Moderatör) #26
Üye Tem 2009 tarihinden beri · 981 mesaj · Konum: Eskişehir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Son hali de bu şekilde olmuş oldu:
import std.stdio, std.string;
 
static int sayac = 0;
auto metin = Metin();
 
struct Metin
{
    string yazı;
    string[int] nitelikler;
    int niteliksayısı = 0;
    
    this(string yazı) 
    {
       this.yazı = yazı;
    }
 
    void ekle (string eklenen) 
    {
        if (nitelikler.length == 0)
            yazı ~= eklenen;
        else if (nitelikler.length == 1) {
            switch (nitelikler[0]) {
            case "koyu":
                foreach (dchar harf; eklenen) {
                    yazı ~= harf;
                    yazı ~= harf;
                }
                break;
            default:
                break;
            }
        }           
    }
    
    string toString() const 
    {
        return format("%s", yazı);
    }
}
 
void ayrıştır (string yazı) 
{
    // dizi içeriğini karakter karakter yaz
    for (int i = 0; i != yazı.length; ++i) {
        writeln(i, " ", yazı[i], " ");
    }
 
    if (yazı.length <= 0) çıkış("dizinin işlenmesi tamamlandı");
 
    // ilk < karakterini bul
    auto ilk = yazı.indexOf('<');
    writeln("ilk karakter: ", ilk);
    
    // yazının başında sadece metin var
    if (ilk > 0) {
        // metin kısmı ekle
        metin.ekle (yazı[0 .. ilk]);
        // eklenen kısmı yazıdan çıkart
        yazı = yazı[ilk .. $];
        // son durumu göster
        writeln("yazının son hali: ", yazı);
        writeln("metinin son hali: ", metin.yazı);
        
        // tekrar başa dön
        ayrıştır(yazı);
 
    } else if (ilk == 0) {
        // en başta bir etiket var mı
        if (yazı[0 .. 3] == "<b>") {
            // koyu özelliğini aç
            metin.nitelikler = [sayac:"koyu"];        
            // yazının en başını kısalt
            yazı = yazı[3 .. $];
            writeln("Yazının son hali: ", yazı);
            writeln("koyu yaptım");            
            ayrıştır(yazı);
        } else if (yazı[0 .. 3] == "<u>") {
            // yazının en başını kısalt
            yazı = yazı[3 .. $];
            writeln("Yazının son hali: ", yazı);
            writeln("büyük yaptım");
            ayrıştır(yazı);
            
        }
 
        if (yazı[0 .. 4] == "</b>") {
            // yazının en başını kısalt
            yazı = yazı[4 .. $];
            writeln("Yazının son hali: ", yazı);
            writeln("</b> etiketini attım");
            metin.nitelikler.remove(metin.nitelikler.length - 1);
        }
        
    }
}
 
void çıkış(string mesaj) 
{
    writeln(mesaj);
    
}
 
void main() 
{
    auto yazı = "Deneme yaparken<b>matematiğe</b>";
    ayrıştır(yazı);    
 
    writeln(metin);
}
acehreli (Moderatör) #27
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ı
Doğru işlediğini biraz da birim testlerinden duymak isteriz. ;)

Bir kaç not ekledim:

/*
 * [Ali] Global değişkenler eninde sonunda sorun doğururlar. Taze örnek (C++
 * ama farketmez): bizim firmada iki farklı grup daha geçen hafta global
 * değişkenlerin ilklenme ve sonlanma sıralarının tanımlanmamış olmasının
 * neden olduğu hatalarla uğraştılar.
 */
 
/*
 * [Ali] Bu herhalde eskinden kalmış olmalı. Değeri programda hiç
 * değişmiyor. Ne olursa olsun, kullanıldığı yere yakın tanımlanmalı. Örneğin
 * belki de yalnızca ayrıştır() tarafından kullanılıyordur.
 */
static int sayac = 0;
 
/*
 * [Ali] Bu daha büyük bir sorun. En azından ileride gerekse, programda
 * belirli bir anda ancak tek metin ayrıştırılabilir. ayrıştır()'ı çağıranlar
 * bunun global olduğunu bilmek zorundadırlar ve hemen kopyalamaları gerekir.
 *
 * ayrıştır() gibi işlevlerin kendi işleri için kullandıkları global veya
 * static değişkenler onları 'non-reentrant' (iki kere çağrılamayan)
 * yapar. ayrıştır() için öyle bir sorun düşünemiyorum ama globallerden
 * kaçınmak gerektiği için sözü uzatıyorum. :)
 *
 * Çözüm: metin, ayrıştır() tarafından döndürülmelidir:
 *
 *    Metin ayrıştır(string yazı) { ... }
 */
auto metin = Metin();
 
// [Ali] ...
 
                foreach (dchar harf; eklenen) {
                    /*
                     * [Ali] Buradan "koyu" yazının her zaman için iki harfle
                     * gösterildiğini anlıyoruz. Ama eğer çıkış biriminin ne
                     * olduğunu biliyorsak zaten Metin diye bir türe gerek
                     * bile yoktur. Girişi baştan sonra okuyarak bir string
                     * üretebiliriz.
                     *
                     * Oysa Metin türü yalnızca metni tarif etse, ondan sonra
                     * ona "kendini konsola gönder", "kendini dosyaya gönder",
                     * vs. diyebiliriz.
                     *
                     * Yani Metin'in gücü, metin düzenini tarif etmesinde
                     * duruyor.
                     */
                    yazı ~= harf;
                    yazı ~= harf;
 
// [Ali] ...
 
    string toString() const 
    {
        /* [Ali] Bu da zamanla basitleşmiş olmalı; yoksa bu haliyle doğrudan
         * yazı da döndürülebilir. */
        return format("%s", yazı);
    }
}
 
void ayrıştır (string yazı) 
{
    /*
     * [Ali] İstediğin bu olmayabilir ama aklımda taze olduğu için
     * hatırlatıyorum.
     *
     * Aralıklar dersinde çok yeni yazdığım gibi, eğer std.array * eklenirse
     * ve yazı bir InputRange olarak kullanılırsa, UTF kod birimleri değil,
     * harfler görünür. Gerekenler:
     *
     * 1) import std.array;
     *
     * 2) InputRange olarak kullanmak; yani
     *
     * 2a) ya for yerine foreach,
     *
     * 2b) ya da for döngüsünde yazı.empty, yazı.front, ve yazı.popFront()
     *     diye InputRange işlevleri kullanmak
     *
     * (Dikkat: o işlem sırasında yazı tükenebilir. :D Onun için bir dilim
     * tüketmemiz gerekebilir.)
     */
    // dizi içeriğini karakter karakter yaz
    for (int i = 0; i != yazı.length; ++i) {
        writeln(i, " ", yazı[i], " ");
    }
 
    /* [Ali] Önemsiz ayrıntı: length'in türü işaretsiz olduğu için sıfırdan
     * küçük olamaz. */
    if (yazı.length <= 0) çıkış("dizinin işlenmesi tamamlandı");

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:
Sayfa:  önceki  1  2 
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-22, 07:02:34 (UTC -08:00)