Forum: Projeler trileri RSS
cmpAbc'yi otomatik olarak oluşturmak
acehreli (Moderatör) #1
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: cmpAbc'yi otomatik olarak oluşturmak
Türk alfabesinden başka alfabeleri de (ve şapkalı harfleri de) desteklemeyi kolaylaştırmak için aklıma bir fikir geldi: cmpAbc'yi otomatik olarak oluşturabilir miyiz?

Bu eşleme tablosunu trileri'den kopyalayarak yazdırırsak:

import std.cstream;
 
/*
 * Sıralanmalarının düzeltilmesi gereken harflerin sıra numaraları
 */
private static immutable double[dchar] cmpAbc;
 
static this()
{
    cmpAbc =
    [
        'ç' : 'c' + 0x0.8p0,
        'ğ' : 'g' + 0x0.8p0,
        'ı' : 'h' + 0x0.8p0,
        'ö' : 'o' + 0x0.8p0,
        'ş' : 's' + 0x0.8p0,
        'ü' : 'u' + 0x0.8p0,
        'Ç' : 'C' + 0x0.8p0,
        'Ğ' : 'G' + 0x0.8p0,
        'İ' : 'I' + 0x0.8p0,
        'Ö' : 'O' + 0x0.8p0,
        'Ş' : 'S' + 0x0.8p0,
        'Ü' : 'U' + 0x0.8p0
    ];
}
 
void main()
{
    foreach (karakter, sıraNumarası; cmpAbc) {
        dout.writefln(karakter, ": ", sıraNumarası);
    }
}

Çıktısı şöyle oluyor:

Ç: 67.5
İ: 73.5
ı: 104.5
Ö: 79.5
Ü: 85.5
ç: 99.5
ö: 111.5
ü: 117.5
Ş: 83.5
ş: 115.5
Ğ: 71.5
ğ: 103.5

Yani 0x0.8p0, aslında onaltılı sistemde yazılmış 0.5 değeri. Örneğin ç için 99.5 çıkıyor, çünkü 'c'nin ASCII kodu 99, ve ona .5 eklenince 'ç' için 99.5 oluyor.

Bu tabloyu elle yazmak zahmetli ve hataya açık. Onun yerine, şu dizgiden yola çıksak, yukarıdaki tabloyu otomatik olarak oluşturabilir miyiz:

"aâbcçdefgğhıîijklmnoöpqrsştuûüvwxyz"

Tabii otomatik olarak oluşturulan eşleme tablosunda yalnızca özel olanlar değil; bütün alfabe bulunacaktır. Sorun değil...

Yani şu eşlemeleri istiyor olalım:

a: 97
â: 97.5
b: 98
c: 99
ç: 99.5
...

Algoritma bu dizgide ilerler, sıra dışında gördüklerine yarımlı değerler atar. Örneğin 'â' karakterinin değeri 226'dır. Kendisinden önceki 'a'nın değeri 97, ve kendisinden sonraki 'b'nin değeri '98' olduğu için 'â'nın sıra dışı olduğunu anlar ve ona 'a' ile 'b'nin ortasındaki değeri verir...

Ben yalnızca döngüsünü kuruyorum; ilginç bulanlar tamamlasın lütfen... :) Şimdilik yalnızca ekrana yazdırmak yeterli:

import std.cstream;
 
void main()
{
    dstring alfabe = "aâbcçdefgğhıîijklmnoöpqrsştuûüvwxyz";
 
    foreach (harf; alfabe) {
        double sıraNumarası = harf;
        dout.writefln(harf, ": ", sıraNumarası);
    }
}

Sıra numaraları "sıralı" olsun...  :-p

Ali
canalpay (Moderatör) #2
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Doğru düzgün yapamadım ama şu yaptığım kodlar dediğiniz işlevi görüyor:

import std.cstream;
 
void main()
{
    dstring alfabe = "aâbcçdefgğhıîijklmnoöpqrsştuûüvwxyz";
    int alfabedekiSıra =0;
    int sıra =0;
    int değer = 97;
    foreach (harf; alfabe) {
        double sıraNumarası = harf;
        if((alfabedekiSıra+değer)==sıraNumarası){
            dout.writefln(harf, ": ", sıraNumarası);
            ++alfabedekiSıra;
            ++sıra;
        }else{
            double deneme=alfabe[sıra-1]+0x0.8p0;
            ++sıra;
            dout.writefln(harf," : ", deneme);
        }
 
    }
}

Ama size ilginç bir şey göstereceğim.(Eğer programı derlerseniz hatanın nedenini burada anlarsınız.)

"aâbcçdefgğhıîijklmnoöpqrsştuûüvwxyz"

Bu yüzden 0.5 vermemeliyiz değil mi ? Bunun yerine onluk sistemde 0.2 versek olmaz mı?

ı=>100 olsa
î=>100.5
i=>101

0.2 için:
ı=>100 olsa
î=>100.2
i=>100.4
i=>100.6
olur.
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Çok güzel. :)

Bir öneri: eğer sıra'yı da foreach'ten edinirsen, kendin tanımlamak ve ++sıra yazmak zorunda kalmazsın:

    foreach (sıra, harf; alfabe) {

(foreach'i kendi türlerimiz için de opAssign ile yapabiliyoruz; ama ben daha hiç denemedim.)

Bu yüzden 0.5 vermemeliyiz değil mi ? Bunun yerine onluk sistemde 0.2 versek olmaz mı?

O da bir aralığa 10 tane yerleştirecektir. Daha küçük bir değer olur, ama her zaman için sınırlı olacaktır. Eğer bu soru sana hâlâ ilginç geliyorsa, o değerin ne kadar küçük olması gerektiğini de algoritma bulsa?

0x0.8p0 gibi olması gerekmiyor.

Alfabedeki harfleri tamamen karıştırdığımızda da doğru bir sıra elde edebilir miyiz? Örneğin "axbşkz"? Aşağıda Azeri alfabesinin X harfi sorun çıkartabilir örneğin.

Bu soru fikir olarak aklıma geldi. Acil olarak gerekmiyor. Sonuçta bir kaç tane alfabe var. Şunlar, ve belki bir kaç tane daha:

// Azeri (az)
"abcçdeəfgğhxıijkqlmnoöprsştuüvyz"
"ABCÇDEƏFGĞHXIİJKQLMNOÖPRSŞTUÜVYZ"
 
// Türkmen (tk)
"abçdeäfghijžklmnňoöprsştuüwyýz"
"ABÇDEÄFGHIJŽKLMNŇOÖPRSŞTUÜWYÝZ"
 
// Türk (tr)
"abcçdefgğhıijklmnoöprsştuüvyz"
"ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ"
 
// Tatar (tt)
"aäbcçdefgğhıiíjklmnñoöpqrsştuüvwxyz"
"AÄBCÇDEFGĞHIİÍJKLMNÑOÖPQRSŞTUÜVWXYZ"

Bence şapkalı harfler de her alfabedeki asıllarının yanlarında durmalı. Hepsi de elle yapılabilir tabii. :) Program ilginç olabilir diye düşündüm. Acil değil...

Ali
canalpay (Moderatör) #4
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bence dediğiniz gibi  bir algoritma kurulması çok zor. Bir alfabe öbüründen çok farklı.
Ama şöyle birşeye ne dersiniz ?

Alfabenin ilk harfinin dchar değerini alacak(Türk alfabesi a:97 ). Daha sonra son harfinin değerini alacak(Türk alfabesi z:122). Sonra alfabenin kaç harfe sahip olduğunu anlayacak(Türk alfabesi:29+â,î). Daha sonra z'yi yakalaması için bir defada ne kadar artması gerektiğini anlayacak. Ona göre alfabeyi arttıracak. Bence kesin çözüm bu. Sizce?
acehreli (Moderatör) #5
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Güzel...

Bence doğru, ama şöyle bir kuralı da uygulamak ister miyiz? Örneğin Türk alfabesinde X geldiği zaman, ASCII'deki yerinde durmasını istiyor olalım.

O zaman senin önerdiğin (ve benim de beğendiğim :) ) a'dan z'ye olan aralığı eşit olarak bölmek işe yaramayabilir. Çünkü örneğin içinde ASCII harflerden birisi bulunmayan bir alfabe, bu algoritma o harfi gözardı ettiği için o harfin yanlış bir noktaya düşmesine neden olabilir.

Bunu önlemenin iki yolu var:

1) Kolay yol: Eğer ASCII karakterlerin belirli bir sırada durmalarını istiyorsak, o zaman onları da alfabe dizgisinin içine yazarız:

"aâbcçdefgğhıîijklmnoöpqrsştuûüvwxyz"

Şimdi farkettim: Zaten ilk dizgide dahil etmişim. Bugünlerde kafam yoruldu herhalde. :) Yani zaten bir sorun yok.

2) Uzun ve gereksiz :) yol: Söylediğin a'dan z'ye algoritmasını, alfabenin içinde yerel olarak uygulamak. Örneğin h'den i'ye, araya iki tane sıkıştıracak şekilde.

Ama birinci yol yeterli zaten.

Ali
canalpay (Moderatör) #6
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Bu arada şöyle bir denemem oldu:
import std.stdio;
void cmpAbc_hesapla()
{
    dstring türk_abc="abcçdeəfgğhxıijkqlmnoöprsştuüvyz";
    int uzunluk=türk_abc.length;
    int ilk_u=cast(int)(türk_abc[0]);
    int son_u=cast(int)(türk_abc[uzunluk-1]);
    int aralık = son_u-ilk_u;
    double artış = cast(double)((aralık))/cast(double)(uzunluk-1);
 
    foreach(i,imge;türk_abc){
        writeln((ilk_u)+(artış*i));
    }
}
 
 
void main(){
    cmpAbc_hesapla();
}

Bazı yerlerde gereksiz değişken tanımlamamın nedeni, neyin ne olduğunu görmek istememdi. Zaten derleyici bu sorunu en iyileştirme ile halletmiştir değil mi :-)
acehreli (Moderatör) #7
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
Bu arada şöyle bir denemem oldu:

Tabii ki çok güzel. Ama... :)

Kesirli sayıların sorunlarını hatırlarsak, artış gibi bir değer tam olarak ifade edilemeyebilir.

Kesirli sayılar sayfasında, 0.1'in tam olarak ifade edilememesiyle ilgili şu örnek vardı:

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

import std.stdio;
 
void main()
{
    float sonuç = 0;
 
    // Bu döngünün 1000 kere tekrarlandıktan sonra 1 değerine
    // ulaşacağını düşünürüz:
    while (sonuç < 1) {
        sonuç += 0.001;
    }
 
    // Bakalım doğru mu...
    if (sonuç == 1) {
        writeln("Beklendiği gibi 1");
    } else {
        writeln("FARKLI: ", sonuç);
    }
}

Benzer şekilde, eğer artış tam olarak ifade edilemiyorsa, ondan yola çıkılan değerler de tam ifade edilemiyor olabilirler.

Aslında başından beri sıralama için kesirli sayı kullanmanın doğru olmadığını biliyorum. Zaten o yüzden bilgisayarlarda tam olarak ifade edilebildiği garantili olan 0x0.8p0 küsur değerini kullanıyordum.

O değer, 0.5 değeridir ve tam olarak ifade edilebilir. Onun yarısı olan değerler, ve o değerlerin toplamlarından oluşan değerler de, duyarlık yettiği sürece tam olarak ifade edilebilirler: 0x0.4p0, 0x0.2p0, 0x0.1p0, vs. (veya örneğin bu üçünün toplamı olan 0x0.7p0)

Şu program, bu değerleri daha değişik bir düzende gösteriyor:

import std.cstream;
 
void main()
{
    double başlangıç = 1;
 
    foreach (i; 0 .. 10) {
        dout.writefln("%a", başlangıç);
        başlangıç /= 2;
    }
}

Bendeki çıktısında 1 için 0x8p-3 yazıyor. (O, 8 değerinin 3 kere ikiye bölüneceği anlamına gelir.)

Sonuçta, iki yoldan birisini seçmek gerek:

a) Kesirli sayı kullanılacaksa, tam olarak ifade edilebilen değerler kullanılmalı. (Baştan da dediğim gibi, bunu elle yazabiliriz; ama sıraları otomatik olarak bir programa yaptırmak da ilginç bir problem :) )

b) 64-bit değerler kullanacağız. Bu daha iyi olabilir; çünkü tamsayı işlemleri zaten kesirli sayılardan daha hızlıdır. Bunun için, her Unicode değerini 32 bit sola kaydırabiliriz. Son 32 bit ise yalnızca özel karakterler için, yani bir anlamda küsurat için kullanılır.

Çok kısaca, şu programın ürettiği gibi değerler olabilir:

import std.cstream;
 
long sıraDeğeri(dchar karakter)
{
    return (cast(long)karakter) << 32;
}
 
void main()
{
    long[dchar] sıralar = [ 'ğ' : sıraDeğeri('g') + 1,
                            'ı' : sıraDeğeri('h') + 1,
                            ];
 
    dstring alfabe = "gğhıi";
 
    foreach (karakter; alfabe) {
        auto tablo_değeri = karakter in sıralar;
        auto sıra = tablo_değeri ? *tablo_değeri : sıraDeğeri(karakter);
 
        dout.writefln("%s: %#x", karakter, sıra);
    }
}

imge

Bu arada, alfabe harflerini ve başka karakterleri de ifade etmek içinE "imge" mi daha uygun yoksa "im" mi? Ben de baştan imgeyi düşünmüştüm ama sözlük anlamı olarak im daha yakın geliyor. Ne dersiniz?

Bazı yerlerde gereksiz değişken tanımlamamın nedeni, neyin ne olduğunu görmek istememdi.

Ben de öyle yaparım zaten. :) Daha önce gerçekten gereksiz olduğunu düşündüğüm değişkenler için söylediklerim seni caydırmasın.

Zaten derleyici bu sorunu en iyileştirme ile halletmiştir değil mi :-)

Doğru.

Ali
canalpay (Moderatör) #8
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Dediklerinize katılıyorum. Son bir defa daha düşünüeceğim.
Bu arada, alfabe harflerini ve başka karakterleri de ifade etmek içinE "imge" mi daha uygun yoksa "im" mi? Ben de baştan imgeyi düşünmüştüm ama sözlük anlamı olarak im daha yakın geliyor. Ne dersiniz?

İmge'nin anlamı: Bizim sandığımızdan çok farklı anlamları var:http://www.tdk.org.tr/TR/Genel/SozBul.a…?F6E10F8892433CF…
Şiirde de kullanılıyor :-)

İm: İşaret anlamında olduğu için oyum im sözcüğüne ama şöyle bir sözcük nasıl:
Tamga(damga): Bazı sitelerde görmüştüm hoşumada gitmişti :-) (Buda işaret anlamında da olsa harfleri belirtmek için çok kullanıyorlar. Görktürk tamgaları.(harfleri...)(Şuan ki abc... gibi bildiğimizden farklı harfleride belirttiği için kullanabiliriz. ))
acehreli (Moderatör) #9
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
canalpay:
Tamga(damga): Bazı sitelerde görmüştüm hoşumada gitmişti :-) (Buda işaret anlamında da olsa harfleri belirtmek için çok kullanıyorlar. Görktürk tamgaları.(harfleri...)(Şuan ki abc... gibi bildiğimizden farklı harfleride belirttiği için kullanabiliriz. ))

Fazla mantıklı! :) Beğendim...

Ali
canalpay (Moderatör) #10
Kullanıcı başlığı: Can Alpay Çiftçi
Üye Tem 2009 tarihinden beri · 1133 mesaj · Konum: İzmir
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
b) 64-bit değerler kullanacağız. Bu daha iyi olabilir; çünkü tamsayı işlemleri zaten kesirli sayılardan daha hızlıdır. Bunun için, her Unicode değerini 32 bit sola kaydırabiliriz. Son 32 bit ise yalnızca özel karakterler için, yani bir anlamda küsurat için kullanılır.


Bu ve verdiğiniz örneği çok iyi anlayamadım. Ama şu biçimde yapabilir miyiz ?
1. Verdiğim kodlardaki gibi çalışacak.
2. Eğer eşlenmiyorsa o sayıya en yakın sayı(tamga) kabul edilecek. Örn
¢=65.2241 olması gerekiyorken ¢=65.2241021 oldu. Program en yakın 65.2241 değerine en yakın değeri atayacak.(Doğal olarak çok az daha hız kaybı demek. )
acehreli (Moderatör) #11
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4508 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
65.2241 olması gerekiyorken ¢=65.2241021 oldu

Ben de bunu anlamadım galiba. Kod görürsem anlarım belki. Ama kesirli sayılar gerçekten doğru çözüm değil. :)

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: Projeler trileri 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-10-18, 07:59:24 (UTC -07:00)