Forum: Ders Arası RSS
Otomatik olarak düzenli ifade oluşturmak
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4448 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Otomatik olarak düzenli ifade oluşturmak
Geçen gün İngilizce forumdaki bir soruya yanıt yazdım. Sonuçtaki program (henüz son kullanıma hazır olmasa da) D'nin ne kadar güçlü olduğunu gösterdi:

  http://forum.dlang.org/thread/oscliyovyysbxmdhyafe@forum.d…

Phobos'ta bir düzenli ifade modülü var: std.regex. Hatta, bu modülün ctRegex olanağı, düzenli ifadeyi ayrıştırma düzeneğini derleme zamanında oluşturan ve bu yüzden çalışma zamanında hız kazandıran bir olanaktır.

Düzenli ifadelerin bir sorunu, ayrıştırma işleminin tarifinin çok karmaşık olabilmesidir. Örneğin, yukarıdaki sorudaki ayrıştırma işi şuydu: "Önce parantezler arasında int değer gelecek, sonra tek char gelecek, sonra da yine parantezler arasında bir double değer gelecek." Amaç, verilen bir dizgiyi buna göre ayrıştırmak ve o tarife uyan yerlerdeki int, char, ve double değerleri bir çokuzlu olarak döndürmek. Bunu yapan bir düzenli ifade dizgisi aşağıdaki gibidir:
    `[(]([0-9]+)[)](.)[(]([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)[)]`
Soruyu soran kişi onun yerine şöyle bir tarif olabilir mi diye sormuştu:
    decode!("(", int, ")", char, "(", double, ")")
Dikkat ederseniz yukarıda Türkçe ifade olarak yazdığımın aynısı ama şablon parametreleri halinde veriliyor.

Yukarıdaki bağlantıdaki programı hem biraz düzelttim hem Türkçeleştirdim:
import std.stdio;
import std.string;
import std.regex;
import std.typecons;
import std.conv;
import std.algorithm;
import std.range;
 
template regexSınıflandırması(T) {
    static if (is (T == int)) {
        // Uyarı: "012"yi ondalık olarak alır ve değeri 12 olur. Yani, değeri
        // 10 olan sekizli olarak değil.
        enum regexSınıflandırması = `[0-9]+`;
 
    } else static if (is (T == char)) {
        enum regexSınıflandırması = `.`;
 
    } else static if (is (T == double)) {
        enum regexSınıflandırması = `[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?`;
 
    } else {
        static assert(false,
                      format("'%s' türü henüz desteklenmiyor.", T.stringof));
    }
}
 
string regexEscape(string s) {
    // TODO: Bu diziye başka karakterler de eklemek ve işlevin mantığını
    // düzeltmek gerekiyor.
    enum özelRegekKarakterleri = [ '(', ')' ];
 
    return s.map!(c => (özelRegekKarakterleri.canFind(c)
                        ? format("[%s]", c)
                        : format("%s", c)))
        .joiner
        .text;
}
 
auto ayrıştırmaParametreleriniAyrıştır(Args...)(string uyanElemanİsmi) {
    string regexDizgisi;
    string çokuzluDöndürmeİfadesi = "return tuple(";
 
    size_t uyanınNumarası = 1;
 
    foreach (arg; Args) {
        static if (is (arg)) {
            regexDizgisi ~= format("(%s)", regexSınıflandırması!arg);
            çokuzluDöndürmeİfadesi ~=
                format("%s[%s].to!%s, ",
                       uyanElemanİsmi, uyanınNumarası, arg.stringof);
            ++uyanınNumarası;
 
        } else static if (is (typeof(arg) == string)) {
            regexDizgisi ~= regexEscape(arg);
 
        } else {
            static assert(false, format("'%s' ifadesi geçersiz.", arg));
        }
    }
 
    çokuzluDöndürmeİfadesi ~= ");";
    return tuple(regexDizgisi, çokuzluDöndürmeİfadesi);
}
 
auto ayrıştır(Args...)(string s) {
    enum ayrıştırmaDizgileri = ayrıştırmaParametreleriniAyrıştır!Args("e");
 
    enum regexDizgisi = ayrıştırmaDizgileri[0];
    enum çokuzluDöndürmeİfadesi = ayrıştırmaDizgileri[1];
 
    enum r = ctRegex!regexDizgisi;
 
    // Ne olup bittiğini gözlemlemek için kullanılabilir:
    // pragma(msg, regexDizgisi);
    // pragma(msg, çokuzluDöndürmeİfadesi);
 
    auto uyum = s.match(r);
 
    if (uyum) {
        // Aynı satırda birden fazla uyum olduğunda birden fazla eleman
        // olur. Biz burada ilk elemanı kullanıyoruz ve gerisini gözardı
        // ediyoruz. (Tabii o yüzden foreach'e de gerek yok ama genel
        // kullanımı göstermesi açısından çıkartmadım.)
        foreach (e; uyum) {
            mixin (çokuzluDöndürmeİfadesi);
        }
    }
 
    // D'nin başka bir kolaylığı: typeof(return), "bu işlevin dönüş türü"
    // anlamına gelir. O tür yukarıda mixin ile katılan çokuzluDöndürmeİfadesi
    // içinde gizli olduğundan burada haberimiz bile olmayabiliyor. O yüzden
    // burada bu kolaylıktan yararlanıyoruz.
    return typeof(return)();
}
 
void main() {
    auto t = ayrıştır!("(", int, ")", char, "(", double, ")")("(1)-(2.5)");
    writeln(t);
 
    // Birden fazla kere kullanılacak olan bir ayrıştırıcı oluşturuyoruz.
    auto ayrıştırıcı = (string s) => ayrıştır!(int, "/", double)(s);
 
    // Bütün elemanlara aynı ayrıştırıcıyı uyguluyoruz.
    auto ayrıştırılanlar = ["1/1.5", "2/2.5", "3/3.5"]
                           .map!ayrıştırıcı;
 
    writeln(ayrıştırılanlar);
}

Ali
kerdemdemir #2
Üye Eyl 2013 tarihinden beri · 94 mesaj · Konum: Danimarka
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Ali Hocam,

Bu ara boost spirit 'e bakıyorum sizde spirit 'i anlatan konferanslara katıldığınızı adamların C++'daki sentaks zorlukları yüzünden taklalar atmak zorunda kaldığını söylemiştiniz(yanlış hatırlamıyorsam bazı operatörleri kullanamıyorlardı bunun için tuhaf taklalar atmak zorun kalıyor demiştiniz İstanbulda buluşmamızda).

Acaba D ile boost spirit ile aynı işlevi görecek "parser domain" dili yazılabilir mi? Ve D deki olanaklar sayesinde parse etme işlerinde C++'ın önüne geçilebilirmi?

Erdemdem
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4448 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Eğer string olarak tanımlamak kabulse Pegged var:

  https://github.com/PhilippeSigaud/Pegged

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-08-16, 20:42:36 (UTC -07:00)