Thread overview
Dönüştürme Yöntemleri
Dec 31, 2022
Salih Dincer
Dec 31, 2022
Ali Çehreli
Dec 31, 2022
Salih Dincer
Dec 31, 2022
Ali Çehreli
Jan 01, 2023
Salih Dincer
Jan 02, 2023
Salih Dincer
December 31, 2022

Türkiye'de 2'lerden birini (2022 -> 3) uğurlamaya saatlerin kaldığı şu dakikalarda! 😀

Rikki'nin (sanırım takma ismi) yabancı forumda işaret ettiği noktaya takıldım; aslında katılım sağlayanlarla birlikte yol aldık ama sanırım hala anlamadığım kısımları var...

Her şey "karışık" (mixed) string türünden uzaklaştığım ve onun değiştirilebilir olmasını istediğim anda başladı:

  string Chars = "YILBAŞI";
  dchar[] Darr = (cast(dchar[])Chars).dup;

  Chars.length.writeln(": ", Chars.ptr); // 8: 55E1416BDD60
  Darr.length.writeln(": ", Darr.ptr); // 2: 7FE3FF356000

Görüldüğü gibi, başta dönüşüm için herhangi bir kütüphaneden değil typeof() gibi iç dil olanağı olan cast()'den faydalandım. Eee ne var bunda demeyin; The Ghost Rider (Hayalet Sürücü) filminin sonlarına gönderme yapmalıyım. İşte makale fikrinin filizlendiği o replik:

>

"You change, She dies..."
(Dönüşürsen, kız ölür!)

Evet, fark ettiyseniz 8 karakterli kızımız (Chars) bir bakmışsınız 2 karakterli bir şeye benzemeyen hale dönüşmüş. Açıklaması basit ve bu konuda cast()'in bir suçu yok:

Bir dchar, 4 çeker bir Jeep (32 bit) olduğundan her UTF karakter temsil edilebiliyor. Chars için özel opCast() tanımlamadığımız için de 2 x 4 tekerin her birine tek harf (Ş harfi 2 teker!) yerleşiyor. Ancak bize kullanılmasa bile dchar[7] lazım çünkü örneğimizde 7 harfimiz var.

Eğer std.conv'deki to!(dchar[]) kullanılmazsa şu şekilde aptalca düzeltebilirdik:

  import std.stdio;
  char[28] YILBAŞI = 0;

void main()
{
  string Chars = "YILBAŞI";
  foreach(i, Char; Chars[0..5]) {
    YILBAŞI[i * 4] = Char;
  }
  char[2] fixŞ = [ 0x5E, 0x01 ];

  YILBAŞI[20..22] = fixŞ;
  YILBAŞI[24] = 'I';

  writeln(cast(dchar[])YILBAŞI); // YILBAŞI
  Chars.print;
}

Tam olarak fixŞ'ye niye ihtiyaç olduğunu bilmesem de kodlama farklılığından dolayı olduğunu düşünüyorum. Çünkü Ş harfi string içindeyken şöyle:

>

0xC5-0x9E

Herhalde ASCII ile UTF ayrımı yapılabilmesi için belli bir mantığa göre tertiplenmiş olmalı. O yüzden string için "karışık" (mixed) diyorum ya!

(Şimdilik bu kadar, yazacak daha çok şey var! Örneğin stack-heap ve/veya string literal olayı...)

December 31, 2022
On 12/31/22 10:41, Salih Dincer wrote:

>    string Chars = "YILBAŞI";
>    foreach(i, Char; Chars[0..5]) {

string'ler UTF-8 kodlamaları olduklarından [0..5] dilimlemesini ancak ve ancak içeriğin ne olduğunu bildiğinde yapabilirsin. Tamam, YILBA'nın karakterlerinin UTF-8 kodlamalarının tek karakterden oluştuğunu bildiğinden bunu yapabiliyorsun ama genelde kullanılamayan bir yöntem olduğundan bu çabayı da tam anlamıyorum. Herhalde öğrenmek için...

O zaman bildiğimi söyleyeyim: Hayır, string içinde [0..n] diye dilimleme yapılmamalıdır.

>      YILBAŞI[i * 4] = Char;

O işlem ancak littleEndian bir sistemde çalıştığında doğru. (Öyle olduğunu anlıyoruz; yoksa değiştirirdin.)

>    }
>    char[2] fixŞ = [ 0x5E, 0x01 ];
>
>    YILBAŞI[20..22] = fixŞ;
>    YILBAŞI[24] = 'I';

Tabii ki onları anlayamam ama bir takım UTF-8 kodlarını oralara yerleştiriyorsun.

> Ş harfi string
> içindeyken şöyle:
>
>> 0xC5-0x9E

Bu işi böyle denemelerle de anlayabilirsin ama bence daha kolayı var: UTF-8'i anlamak.

> Herhalde ASCII ile UTF ayrımı yapılabilmesi için belli bir mantığa göre
> tertiplenmiş olmalı.

Evet! Bunu daha önce konuşmuştuk. UTF-8'in ne olduğu Wikipedia'da veya başka kaynaklarda var.

> O yüzden string için "karışık" (mixed) diyorum ya!

Bence deme çünkü bir karışıklık yok. Yalnızca UTF-8 var. :)

Anlıyor muyum: UTF-8'in ASCII ile karışık olduğunu mu söylemek istiyorsun? O, UTF-8'in akıllıca tasarlanmış olmasından geliyor: Mevcut ASCII belgeler UTF-8 olabilsinler diye o karakterlerin UTF-8 kodlamaları ASCII kodlarıyla aynı seçilmiştir.

Ali

December 31, 2022

On Saturday, 31 December 2022 at 19:02:57 UTC, Ali Çehreli wrote:

>

Bence deme çünkü bir karışıklık yok. Yalnızca UTF-8 var. :)

Anlıyor muyum: UTF-8'in ASCII ile karışık olduğunu mu söylemek istiyorsun? O, UTF-8'in akıllıca tasarlanmış olmasından geliyor: Mevcut ASCII belgeler UTF-8 olabilsinler diye o karakterlerin UTF-8 kodlamaları ASCII kodlarıyla aynı seçilmiştir.

İngilizce karışık sözcüğünü kullanmadığım için karışıklık anlamı vermek istemedim ama evet, şimdi hatırladım UTF-8'de akıllı bir tasarım vardı. Mesela ş harfi için örnek verilmiş:

=== Örnekler ===

ş harfinin UTF-8 ile nasıl kodlanacağını inceleyelim:

  • ş harfinin Unicode kod noktası U+015F'tir.
  • Kod noktası U+0080 ve U+07FF aralığında olduğu için tabloya göre en az iki baytlık kalıbın içine sığabileceği anlaşılmaktadır.
  • On altı tabanındaki 01-5F sayısı iki tabanında 001 0101 1111 şeklinde gösterilmektedir. Soldaki iki adet sıfır tablodaki kalıpta 11 bitlik boş yerin tamamını kaplamak için eklenmiştir.
  • Kodlanmış karakterimiz iki kod biriminden oluşacağı için ilk kod birimi iki adet 1 ve devamında bir adet 0 ile başlamaktadır. (110xxxxx)
  • Kalan beş hane kod noktamızın ilk beş hanesiyle doldurulur (11000101).
  • Mavi renkli kısım yerleştirildiği için kod noktamızdan geriye yeşil renkle gösterilen 6 hane kalmıştır (001 0101 1111).
  • İkinci kod birimimiz kural gereği 10 ile başlamaktadır ve kalan 6 hanesi boştur. (10xxxxxx)
  • Kalan 6 haneyi kod noktamızda kalan bitlerle doldurursak ikinci kod birimimiz (baytımız) de tamamlanmış olur (10011111).
  • Kodlama tamamlanmıştır. U+015F kod noktalı "ş" karakteri UTF-8 kodlamasında 11000101 10011111 şeklinde kodlanmaktadır. İki tabanındaki bu uzun bit dizilimi yazımı daha kolay olsun diye sıklıkla on altı tabanına C5-9F olarak gösterilir.

Barış ve sağlık dolu bir 2023 olsun, iyi yıllar...

December 31, 2022
On 12/31/22 11:41, Salih Dincer wrote:

> İngilizce karışık sözcüğünü kullanmadığım için karışıklık anlamı vermek
> istemedim

Ben yine de doğru anlammışım. :)

> * ş harfinin Unicode kod noktası `U+015F`'tir.

Yani 8 bite sığmaz.

> * Kodlanmış karakterimiz iki kod biriminden oluşacağı için ilk kod
> birimi iki adet 1 ve devamında bir adet 0 ile başlamaktadır. (110xxxxx)

O 110'ın anlamı: Bu karakter iki baytla kodlanmıştır.

> * İkinci kod birimimiz kural gereği 10 ile başlamaktadır

O 10'ın anlamı: Bu, bir devam (continuation) baytıdır. Yani, kurmakta olduğun Unicode karakterine 6 bit daha getiriyorum.

UTF-8 baytlarının yüksek değerli bitleri şu anlamlara gelir:

0: Tek baytlık bir Unicode karakteri başlatıyoruz. Bütün değeri bu baytın son 7 bitindedir.

110: İki baytlık bir Unicode karakteri başlatıyoruz. Değerinin 5 biti burada, 6 biti bir sonraki baytta.

1110: Üç baytlık bir Unicode karakteri başlatıyoruz. Değerinin 4 biti burada, 2x6=12 biti bir sonraki iki baytta.

11110: Dört baytlık bir Unicode karakteri başlatıyoruz. Değerinin 3 biti burada, 3x6=18 biti bir sonraki baytta.

UTF-8 kodlamasının bir güzelliği, kodu açan kod (yani, "decode eden program") dizginin yarım kalıp kalmadığını anlayabilir ve bazı karakterleri gözardı edebilir. Örneğin, 11110 ile başlayan bir bayttan sonra 3 bayt yoksa bu karakteri tamamlayamadık demektir.

Benzer biçimde, dizginin ilk baytı 10 ile başlıyorsa bu ve izleyen bütün 10 baytlarını gözardı edebiliriz çünkü hangi Unicode karakterinin devamı olduklarını bilemeyiz. Kodlamayı açan program öncelikle 10 olmayan bir bayt bulmalıdır.

Ödev: Yukarıdaki mantığın programını yazın.

Kopya: std.utf.decode.

Ali

January 01, 2023

On Saturday, 31 December 2022 at 21:15:10 UTC, Ali Çehreli wrote:

>

Ödev: Yukarıdaki mantığın programını yazın.

Kopya: std.utf.decode.

Aslında tam da SONY ödeviymiş çünkü 50-100 satır arası kodlanabiliyormuş. Verdiğim cevabı geliştirmek ve auto dcharArrayFrom(string encodedText) işlevine ve/veya şablonlu bir yapıya alınabilir ama yeterli sanırım? Aslında basit bir yerde çok vakit kaybettiğim (uyuyup kalkınca aşağıdaki kod çorap söküğü gibi çıktığı) için daha fazla uğraşmak istemiyorum.

import std.format,
       std.stdio;

void main()
{
  string encodedText = "YILBAŞI";
  dchar[] decodedText;
  size_t i, sumNumBytes;/* <-işlenecek bayt sayısı
         ^-sıradaki bayt */
  while(i < encodedText.length)
  {
    const chr = encodedText[i]; /* sıradaki değere
    göre, karakterin kaç bayt olduğunu belirle */
    if(chr >> 7 == 0x00) {

      decodedText ~= cast(char)chr;
      sumNumBytes = 1;         // ilk bit 0 ise
    }
    else if(chr >> 5 == 0x06) {

      wchar decode = (chr & 0x1F) << 6; // 1.'nin 6
      decode |=  encodedText[i+1] & 0x3F; // 2.'nin 5
      decodedText ~= decode;   // bitlerini birleştir
      sumNumBytes = 2;         // MSB bitleri 110 ise
    }
    else if(chr >> 4 == 0x0E) {// TO-DO

      sumNumBytes = 3;         // MSB bitleri 1110 ise
    }
    else if(chr >> 3 == 0x1E) {// TO-DO

      sumNumBytes = 4;         // MSB bitleri 11110 ise
    }
    else throw new Exception (
      format("TANIMLANAMAYAN UTF-8 BAYTI: %08b", chr)
    );
    i += sumNumBytes;
  }

  foreach(dchar c; decodedText)
  {
    c.writefln!"%4X: %s"(c);
  }

  assert(decodedText.length == 7);
} /* ÇIKTISI:
  59: Y
  49: I
  4C: L
  42: B
  41: A
 15E: Ş
  49: I
  */

SDB@79

January 02, 2023

On Sunday, 1 January 2023 at 10:13:35 UTC, Salih Dincer wrote:

>

... daha fazla uğraşmak istemiyorum.

Çok uğraşmadım aslında, kodun geri kalan kısmını OpenAI'ın GPT'sine yazdırdım. Ehh biraz düzenleme gerekti tabi. Çince ve Japonca örneklerle test ettim:

import std.stdio;

auto dcharArrayFrom(string encodedText)
{
  import std.format;

  dchar[] decodedText;
  size_t i, sumNumBytes;/* <-işlenecek bayt sayısı
         ^-sıradaki bayt */
  while(i < encodedText.length)
  {
    const chr = encodedText[i]; /* sıradaki değere
    göre, karakterin kaç bayt olduğunu belirle */
    if(chr >> 7 == 0x00)
    {
      decodedText ~= chr;
      sumNumBytes = 1;         // ilk bit 0 ise
    }
    else if(chr >> 5 == 0x06)
    {
      dchar decode = (chr & 0x1F) << 6;   // 1.'nin 6
      decode |=  encodedText[i+1] & 0x3F; // 2.'nin 5
      decodedText ~= decode;   // bitlerini birleştir
      sumNumBytes = 2;         // MSB bitleri 110 ise
    }
    else if(chr >> 4 == 0x0E)
    {
      dchar decode = (chr & 0x0F) << 12; // 1.'nin 4
      decode |= (encodedText[i+1] & 0x3F) << 6; // 2.'nin 6
      decode |= encodedText[i+2] & 0x3F; // 3.'nin 6
      decodedText ~= decode; //*/
      sumNumBytes = 3;         // MSB bitleri 1110 ise
    }
    else if(chr >> 3 == 0x1E)
    {
      dchar decode = (chr & 0x07) << 18; // 1.'nin 3
      decode |= (encodedText[i+1] & 0x3F) << 12; // 2.'nin 6
      decode |= (encodedText[i+2] & 0x3F) << 6; // 3.'nin 6
      decode |= encodedText[i+3] & 0x3F; // 4.'nin 6
      decodedText ~= decode; //*/
      sumNumBytes = 4;         // MSB bitleri 11110 ise
    }
    else throw new Exception (
      format("TANIMLANAMAYAN UTF-8 BAYTI: %08b", chr)
    );
    i += sumNumBytes;
  }
  return decodedText;
}

void main()
{
  enum {
    besmele = "بسم اللّٰه الرحمن الرحيم", // Arapça
        dil = "\xe8\xaa\x9e", // 語 (Çince)
    yılbaşı = "y\xc4\xb1lba\xc5\x9f\xc4\xb1", // Türkçe
    nihongo = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // 日本語 (Japonca)
  }
  //nihongo.print;
  auto str = dil.dcharArrayFrom();
  writeln;
  //foreach(dchar c; str) c.write;/*
  foreach(dchar c; str)
  {
    c.writefln!"%4X: %s"(c);
  }//*/
}

SDB@79