Jump to page: 1 2
Thread overview
Sabit uzunluklu dizgilerin düşündürdükleri ve ID3v1
Feb 02, 2012
zafer
Feb 03, 2012
Salih Dinçer
Feb 03, 2012
Salih Dinçer
Feb 03, 2012
Salih Dinçer
Feb 03, 2012
Salih Dinçer
Feb 03, 2012
zafer
Feb 07, 2012
zafer
February 03, 2012

Ali eline sağlık, çok güzel olmuş, aslında benimde aklımdan geçenleri kodlara dökmüşsün.

Neticede bende ID3v1 bilgisini okuma ve yazmayı yapan bir kütüphane haline getirmek istiyorum. Bu durumda bu kütüphaneyi kullanan birinin her atamadan önce şöyle bir kod yazması pek güzel olmazdı.

tiketPaketi.başlık = leftJustify("New Title", ID3v1Pakedi.başlık.length, '\0');

Ancak bu tasarımı irdelediğimde benim farklı düşündüğüm noktalar şunlar;

ID3v1Paketi şeklinde yapıya mutlaka ihtiyacımız var. Ancak metodların bir kısmının sınıf içerisinde bir kısmının bu yapıda dağınık durması bence doğru değil. Ben yapıyı en basit anlamında sadece alan tanımları ile sınırlayıp geriye kalan işlemleri sınıf içine taşımanın daha iyi olacağı düşüncesindeyim.

   ID3v1Pakedi opCast(T : ID3v1Pakedi)() const
   {
       return ID3v1Pakedi(başlık, sanatçı, albüm, yıl, mesaj, tarz);
   }

OpCast tür dönüşümü yerine kendi yazdığımız bir metot ile bunu yapabiliriz. Neden opcCast kullandığımızı doğrusu çok anlamadım. Ben şöyle bir metot tasarladım sen ne dersin?

ID3v1Pakedi PaketiOlustur(string baslik, string sanatci, string album, int yil, string mesaj, Tarz tarz)
{
	ID3v1Pakedi paket;

	paket.TAG = "TAG";
	paket.baslik = SabitUzunluklu(baslik, 30);
	paket.sanatci = SabitUzunluklu(sanatci, 30);
	paket.album = SabitUzunluklu(album, 30);
	paket.yil = SabitUzunluklu(to!string(yil), 4);
	paket.mesaj = SabitUzunluklu(mesaj, 30);
	paket.tarz = [ cast(char)tarz ];

	return paket;
}

Son olarak bu kodları bir kütüphane (.so veya .dll) haline getirmek niyetindeyim. Bunun için kodları ayrı bir modüle taşıdım ama başka tanım yapmam gerekiyor mu?

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

February 02, 2012

Sabit uzunluklu dizgilerin düşündürdükleri

Blog gibi bir yazı oldu. :) Çok basit bir konu gibi görünüyor ama bir sürü başka konuyla ilgili.

Şu konudaki ID3v1Pakedi yapısının üyeleri sabit uzunluklu dizgiler olarak tasarlanmıştı:

http://ddili.org/forum/thread/705

mp3 dosyalarının sonundaki ID3v1 pakedine bire bir uyduğu için kolayca okuyup yazabildiğimiz için iyi bir fikir olduğu düşünülebilir. O açıdan doğrudur. Ancak, program içinde kullanım açısından sorunları var. O konuda da görüldüğü gibi, basit bir atama işlemini bile gerçekleştiremiyoruz.

O yapıyı bir kenara bırakalım ve basitçe şu değişkene bakalım:

   char[30] d;
   d = "merhaba";   // <-- çalışma zamanı hatası!

Sol tarafla sağ tarafın uzunlukları tutmadığı için derlenemiyor. Bir çözüm olarak şunu bulmuştuk:

   d = leftJustify("merhaba", d.length, '\0');

Bu konuyu İngilizce forumlarda şurada açtım:

http://dfeed.kimsufi.thecybershadow.net/discussion/thread/jgcfs5$2uss$1@digitalmars.com

Oradan çok daha basit olan yöntemi öğrendim (veya hatırladım :)):

   auto değer = "merhaba";
   d[0 .. değer.length] = değer;    // baş tarafına ata
   d[değer.length .. $] = '\0';     // sonunu '\0' doldur

(Not: Tabii orada 'değer''in hedefe sığacağını varsayıyoruz.)

O yöntem leftJustify'ın içinde de görülüyor:

       retval[0 .. s.length] = s[];
       retval[s.length .. $] = cast(C)fillChar;

Neyse... Tekrar baştaki soruya dönersek, char[N] bir dizgi midir? Rahatça bir dizgi gibi kullanamadığımıza bakarak bence onun dizgi olmadığını kabul etmek gerekiyor.

Daha iyi bir tasarım, mp3 dosyasının sonundaki pakedi açmak ve kullanılabilir bir yapı oluşturmaktır. Program içinde o yapı kullanılır ve dizgilerle rahatça oynanır. En sonunda tekrar dosyaya yazılacağı zaman da nesneye "kendini bir ID3v1 pakedi olarak ifade et" denir. Ve işte o paket dosyaya yazılır.

Dosya sonundaki ID3v1 pakedi aslında şu kavramı temsil ediyor: Şarkı hakkında bilgi. Pakedin sabit uzunluklu dizgilerden oluşan parçaları aslında şarkı bilgisinin yalnızca bir gösterimi.

Bütün bunların ışığı altında ben şöyle bir tasarım önereceğim:

import std.stdio;
import std.string;
import std.exception;
import std.conv;

// bkz. http://www.multimediasoft.com/amp3dj/help/index.html?amp3dj_00003e.htm
enum Tarz { blues /* ... vs. ... */ }

/*
* Bu, program içinde serbestçe kullanacağımız şarkı bilgisini taşıyor. Bu
* sınıf rahat üyelerden oluştuğu için programda çok durumda kullanabiliriz.
*
* Bunun bir üstünlüğü, bu bilgilerin farklı ID3 standartlarını da
* destekleyebilmesidir. Örneğin ID3v1 Unicode'u desteklemediği halde burada
* Unicode harfler kullanabiliriz. Ancak ID3v1 pakedi oluşturulduğunda Türkçe
* harflerin ASCII karşılıklarına dönüştürülmeleri gerekir. O işlem bu sınıfı
* bağlamamalıdır.
*
* Şarkının bilgisi, dosya içindeki gösteriminden farklı bir kavramdır. Bu
* sınıf o yüzden var.
*/
class ŞarkıBilgisi
{
   string başlık;
   string sanatçı;
   string albüm;
   size_t yıl;
   string mesaj;
   Tarz tarz;

   /*
    * Verilen paketten ŞarkıBilgisi oluşturan kurucu işlev
    */
   this(ID3v1Pakedi paket)
   {
       this.başlık = to!string(paket.başlık);
       this.sanatçı = to!string(paket.sanatçı);
       this.albüm = to!string(paket.albüm);
       this.yıl = to!int(paket.yıl);
       this.mesaj = to!string(paket.mesaj);
       this.tarz = cast(Tarz)paket.tarz[0];
   }

   /*
    * Yapılacak bir iş: Burada bir kurucu daha iyi olur. Bu kurucu da başlık,
    * vs. bilgileri normal D türleri olarak alır ve onlardan bir ŞarkıBilgisi
    * oluşturur. Bu programda henüz gerekmediği için yazmadım:
    *
    *    this (string başlık, string sanatçı, vs.) { ... }
    */

   /*
    * Bu dönüşüm işleci ŞarkıBilgisi nesnesinden ID3v1Pakedi
    * oluşturur. Görüldüğü gibi asıl işi ID3v1Pakedi türünün kurucusuna
    * devrediyor.
    */
   ID3v1Pakedi opCast(T : ID3v1Pakedi)() const
   {
       return ID3v1Pakedi(başlık, sanatçı, albüm, yıl, mesaj, tarz);
   }
}

struct ID3v1Pakedi
{
   char[3]  TAG;           // "TAG" belirteci
   char[30] başlık;        // title
   char[30] sanatçı;       // artist
   char[30] albüm;         // album
   char[4]  yıl;           // year
   char[30] mesaj;         // comment
   char[1]  tarz;          // genre   Bunu tek char da yapabilirdik

   /*
    * Bu kurucunun 'tag' bilgisi almadığına dikkat edin. O bilgi bu türün
    * kendisi ile ilgili bir konudur; dışarıdan verilmesi beklenen bir şey
    * değildir.
    */
   this(string başlık,
        string sanatçı,
        string albüm,
        size_t yıl,
        string mesaj,
        Tarz tarz)
   {
       /*
        * Yalnızca bu kurucu tarafından kullanıldığı için bu işlevi böyle
        * içeride tanımladım; başka bir yerde de olabilirdi ve gerekirse
        * taşınabilir.
        *
        * Verilen dizginin sonu '\0' karakterleriyle dolu olmak üzere
        * 'genişlik' kadar uzun olanını döndürür. Dizgi uzunsa kırpar.
        *
        * Daha da yapılması gereken işlem: ID3v1 paketleri yalnızca ASCII ile
        * işliyorlar. 'değer' içindeki Türkçe karakterleri aksansızlarıyla
        * değiştirmek de gerekir.
        */
       string sabitUzunluklu(string değer, size_t uzunluk)
       {
           // Gerekirse kırp
           if (değer.length > uzunluk) {
               değer.length = uzunluk;
           }

           // Sonunun da '\0' ile doldurulmasını sağla
           return leftJustify(değer, uzunluk, '\0');
       }

       this.TAG = "TAG";
       this.başlık = sabitUzunluklu(başlık, 30);
       this.sanatçı = sabitUzunluklu(sanatçı, 30);
       this.albüm = sabitUzunluklu(albüm, 30);
       this.yıl = sabitUzunluklu(to!string(yıl), 4);
       this.mesaj = sabitUzunluklu(mesaj, 30);
       this.tarz = [ cast(char)tarz ];  // Bu üyeyi tek char da yapabilirdik
   }

   static ID3v1Pakedi oku(File dosya)
   {
       immutable dosyaYeri = dosya.tell();
       scope (exit) dosya.seek(dosyaYeri, SEEK_SET);
       dosya.seek(-cast(long)ID3v1Pakedi.sizeof, SEEK_END);

       ID3v1Pakedi[1] paketler;
       dosya.rawRead(paketler);

       ID3v1Pakedi paket = paketler[0];

       enforce (paket.TAG == "TAG",
                format("'%s', bir ID3v1 dosyası değil!", dosya.name()));

       return paket;
   }

   void yaz(File dosya) const
   {
       dosya.seek(-cast(long)ID3v1Pakedi.sizeof, SEEK_END);
       dosya.rawWrite([ this ]);
   }
}

int main(string[] args)
{
   if (args.length < 2) {
       stderr.writefln("Kullanım: %s dosya1.mp3 [dosya2.mp3 [...]]", args[0]);
       return 1;
   }

   foreach (dosyaİsmi; args[1..$]) {
       auto dosya = File(dosyaİsmi, "r+");
       auto paket = ID3v1Pakedi.oku(dosya);

       auto bilgi = new ŞarkıBilgisi(paket);

       writef("%s dosyası için mesaj giriniz: ", dosyaİsmi);
       string mesaj = strip(readln());
       bilgi.mesaj = mesaj;

       /*
        * Buradaki dönüşüm perde arkasında ve otomatik olarak
        * ŞarkıBilgisi.opCast!ID3v1Pakedi() işlevini çağırır
        */
       paket = to!ID3v1Pakedi(bilgi);

       paket.yaz(dosya);
   }

   return 0;
}

Ali

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

February 03, 2012

Sizi hayranlıkla izliyorum... 8-(

(Bir gün katkı da bulunma dileğiyle...)

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

February 03, 2012

Aklıma şimdi bir şey geldi. Sabit uzunlukta olması için, hiç istenen boyutta boş bir veriyle OR'lamayı denediniz mi? Masking gibi bir şeyden bahsediyorum...

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

February 03, 2012

Kusura bakmayın ben de anlamamışım, öncekini hiç yazmadım farz edin...:)

Peki şu aşağıdaki derleme hatası veren satır yerine:

	char[30] d;
	d = "merhaba";   // <-- çalışma zamanı hatası!

Şu satırı niye kullanmıyorsunuz? Hız gibi özel bir nedeni mi var?

	foreach (i, c; "merhaba") d[i] = c;

Sevgiler, saygılar...

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

February 03, 2012

Evet, haklısın...

İşin içerisinde birden fazla karakterli UTF'ler girince işler karışabilir. Ama dediğin gibi bir sorun teşkil etmiyorsa açıkçası benim ilk aklıma gelen ve en kolay gibi görünen 'foreach'. Eğer iki döngü kullanırsak doldurma karakterini de halledebiliriz:

	auto m = "merhaba";
	int i = d.length < m.length ? m.length : 0;
	for ( ; i < m.length; i++) d[i] = m[i];
	for ( ; i < d.length; i++) d[i] = '\0';

Ayrıca ilk satıra küçük bir sorgu ekledim; eğer d'nin uzunluğu m'den küçük olursa hata vermemesi için döngüleri es geçmesini sağlıyor.

Başarılar...

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

February 03, 2012

Alıntı (zafer):

>

ID3v1Paketi şeklinde yapıya mutlaka ihtiyacımız var. Ancak metodların bir kısmının sınıf içerisinde bir kısmının bu yapıda dağınık durması bence doğru değil. Ben yapıyı en basit anlamında sadece alan tanımları ile sınırlayıp geriye kalan işlemleri sınıf içine taşımanın daha iyi olacağı düşüncesindeyim.

Kabul. Bu noktada hiçbir sakınca görmüyorum.

Alıntı:

>
>     ID3v1Pakedi opCast(T : ID3v1Pakedi)() const
>     {
>         return ID3v1Pakedi(başlık, sanatçı, albüm, yıl, mesaj, tarz);
>     }
> ```

>
> OpCast tür dönüşümü yerine kendi yazdığımız bir metot ile bunu yapabiliriz. Neden opcCast kullandığımızı doğrusu çok anlamadım. Ben şöyle bir metot tasarladım sen ne dersin?

Açıklık çok daha iyi. Onun için PaketiOlustur() da iyi. to() türün opCast'ini kullandığı için sanki opCast tanımlanırsa standart kütüphane ile daha bir bir arada gibi olur gibi gelmişti.

Başka ID3 biçimlerini (v2, vs.) de desteklemek gerekecek. O zaman PaketiOlustur() isminde hangi biçimin istendiği de belirtilmeli. to!ID3v1Pakedi(bilgi) dendiğinde ise tür açıkça görülüyor.

Ama gerçekten hiç önemi yok. :) Her işin bir çok yolu var.

Alıntı:
> Son olarak bu kodları bir kütüphane (.so veya .dll) haline getirmek niyetindeyim. Bunun  için kodları ayrı bir modüle taşıdım ama başka tanım yapmam gerekiyor mu?

Ben hiç .so ve .dll ile ilgilenmedim. Linux safasında "shared" geçen yerler:

 http://www.d-programming-language.org/dmd-linux.html

ve Windows sayısı "dll" geçen yerler:

 http://www.d-programming-language.org/dmd-windows.html

Ali

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

Alıntı (Salih Dinçer):

>

Aklıma şimdi bir şey geldi. Sabit uzunlukta olması için, hiç istenen boyutta boş bir veriyle OR'lamayı denediniz mi? Masking gibi bir şeyden bahsediyorum...

Anlamadım. :(

Ali

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

February 03, 2012

Alıntı (Salih Dinçer):

>

Peki şu aşağıdaki derleme hatası veren satır yerine:

Bazı durumlarda önemli olabilir diye: derleme değil, çalışma zamanı. :)

Alıntı:

>
> 	char[30] d;
> 	d = "merhaba";   // <-- çalışma zamanı hatası!
> ```

> Şu satırı niye kullanmıyorsunuz? Hız gibi özel bir nedeni mi var?
>
>

foreach (i, c; "merhaba") d[i] = c;

>

Sevgiler, saygılar...

Evet, daha kolay. Hızını denemedim ama o da copy()'nin yaptığı şey aslında. char UTF-8 kod birimi olduğu için teker teker erişmekten genel olarak korkuyorum ama bu durumda hedef de char olduğu için bir sakınca da yok.

Ali

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

February 03, 2012

Evet, çözüm güzel. :)

Alıntı (Salih Dinçer):

>

İşin içerisinde birden fazla karakterli UTF'ler girince işler karışabilir.

Hedefin eleman büyüklüğü kaynağınkinden uzun olduğunda nasıl sorun olabileceğini gösteren bir örnek (yani char'dan dchar'a atama yaparken):

   dchar[30] d;
   foreach (i, c; "merhaba dünya") {
       d[i] = c;
   }
   writeln(d);

Çıktısı:

'merhaba dünya ...'

(Sonundaki '\xff' karakterlerini yazdırmadım; forumun sayfasını bile bozdular. :) )

Ali

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

« First   ‹ Prev
1 2