Forum: D Programlama Dili RSS
string'in elemanları harf veya Unicode karakteri değil
acehreli (Moderatör) #1
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ı
Konu adı: string'in elemanları harf veya Unicode karakteri değil
D'nin karakter türlerinin Unicode kodlamaları olduğunu biliyoruz. Şu iki sayfada tam olmasa da biraz bilgi var:

  http://ddili.org/ders/d/karakterler.html
  http://ddili.org/ders/d/dizgiler.html

(Hatta onları yazdığım zaman tam anlamamış olabileceğim için yanlış bilgi bile olabilir! :D)

Digital Mars forumunda aynı konu yine açıldı. Sorun, string'in elemanlarına teker teker erişirken görülüyor:

import std.stdio;
 
void harfler_indeks_ile(const char[] dizgi)
{
    for (int i = 0; i != dizgi.length; ++i) {
        write(dizgi[i], ' ');
    }
    writeln();
}
 
void main()
{
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
    harfler_indeks_ile(dizgi);
}

string'in elemanları harf değil, bir kod birimi (code unit); yani harfi UTF-8 kodlamasında oluşturan birimlerin her birisi. Yukarıdaki programın çıktısı, beklendiği gibi, benim Linux konsol ortamında şöyle bozuk oluyor:

a b c � � d e f g � � h � � i j k l m n o � � p q r s � � t u � � v w x y z

Çünkü, string'i oluşturan birimler, yani 'char'lar tek başlarına anlamlı değiller.

Daha ileriye gitmeden önce, kafa karıştıran bir garipliğe dikkat çekmem gerekiyor: Yukarıdaki programda dizgi elemanından sonra yazdırılan boşluk karakterini kaldırın. Yani şu satırı kullanın:

        write(dizgi[i]);

Bu sefer çıktı düzeliyor!

abcçdefgğhıijklmnoöpqrsştuüvwxyz

Bu sonuca bakarsak, string'in elemanlarının teker teker kullanılmasında sakınca olmadığını düşünebiliriz. Çünkü sanki teker teker harfleri yazdırmış gibi oluyor. Ama yanlış! Biz aslında yine de teker teker kod birimlerine erişiyoruz.

Düzgün çıkmasının nedeni, benim Linux ortamımın (belki de bütün Linux ortamlarının?) zaten UTF-8 kodlamasıyla çalışmasından kaynaklanıyor. Sonuçta, benim konsola gönderdiğim kod birimleri arka arkaya yine de anlamlı Unicode karakterleri oluşturuyorlar ve o yüzden de çıktı doğru görünüyor.

Aynı programa üç işlev daha ekleyeceğim:

import std.stdio;
 
void harfler_indeks_ile(const char[] dizgi)
{
    for (int i = 0; i != dizgi.length; ++i) {
        write(dizgi[i], ' ');
    }
    writeln();
}
 
void harfler_foreach_tür_belirtmeden(const char[] dizgi)
{
    foreach (harf; dizgi) {
        write(harf, ' ');
    }
    writeln();
}
 
void harfler_foreach_char_ile(const char[] dizgi)
{
    foreach (char harf; dizgi) {
        write(harf, ' ');
    }
    writeln();
}
 
void harfler_foreach_dchar_ile(const char[] dizgi)
{
    foreach (dchar harf; dizgi) {
        write(harf, ' ');
    }
    writeln();
}
 
void main()
{
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
    harfler_indeks_ile(dizgi);
    harfler_foreach_tür_belirtmeden(dizgi);
    harfler_foreach_char_ile(dizgi);
    harfler_foreach_dchar_ile(dizgi);
}

Çıktısı şöyle:

a b c � � d e f g � � h � � i j k l m n o � � p q r s � � t u � � v w x y z
a b c � � d e f g � � h � � i j k l m n o � � p q r s � � t u � � v w x y z
a b c � � d e f g � � h � � i j k l m n o � � p q r s � � t u � � v w x y z
a b c ç d e f g ğ h ı i j k l m n o ö p q r s ş t u ü v w x y z

Görüldüğü gibi, yalnızca sonuncusu, yani foreach döngüsünde açıkça dchar isteyeni doğru çalışıyor.

Yani, char'ın Unicode karakteri olamadığını, ama Unicode karakterlerinin UTF-8 kodlamasında kullanılan "kod birimleri" olduklarını hatırlayalım. :)

Ali
acehreli (Moderatör) #2
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ı
Aynı programı bir de delegate kullanarak yazdım:

import std.stdio;
 
void dene(string başlık, void delegate() işlem)
{
    writeln(başlık, ':');
    write("  ");
    işlem();
    writeln();
}
 
void main()
{
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
    dene("indeks ile", {
            for (int i = 0; i != dizgi.length; ++i) {
                write(dizgi[i], ' ');
            }
        });
 
    dene("foreach, tür belirtmeden", {
            foreach (harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, char ile", {
            foreach (char harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, dchar ile", {
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}

Gerek yoktu tabii. :) Mengü'nün lambda hatırlatmasının arkasından denemek istedim. :)

Ali
canalpay (Moderatör) #3
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 karakter kodlama ile ilgili olarak trileri projesi bize çok şey kattı. Hatta ilk orada char türünün türkçe için yeterli olamayacağını dchar kullanarak yazmamız gerektiğini söylemiştik.

Benim anladığım eğer Türkçe karakter kullanacak isek asla char türü ile ilişkimiz olmamalı. Eğer tek harf ile ilişkimiz olursa yanlış işler yapabiliriz. Örneğin SDC dosyayı string olarak okuyor ancak okurken kaçıncı satırın yanında kaçın sütunda olduğununda bilgisini tutuyor. Eğer string(char[]) türünü kullanırsa örneğin Türkçe harfler yüzünden bir sütun değil iki sütun ileri gidecek. O yüzden kaçıncı sütunda olduğunu öğrenirken dchar dchar ilerliyor.

Bu karakter işlemleri /n gibi ifadeleri okur iken beni dahada çok karıştırıyor.

Phobos'un kütüphanesi içinde bu geçerli ancak ne düşünüyorlar bilmiyorum. Ben phobos kütüphanesinde şablon kullanılmasa bile en azından in dchar kullanılması taraftarıyım.

Bu arada function yerel işlevde değilde o yerel işlevi kapsayacak değişken ile işlem yapabiliyor mu ? Ben yapabiliyor diye tahmin ediyordum ancak o zaman sizin verdiğiniz örnek kodu delegate yerine function ilede çalıştırabilmemiz gerekiyor. Ancak ben çalıştıramadım.
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ı
Bu arada function yerel işlevde değilde o yerel işlevi kapsayacak değişken ile işlem yapabiliyor mu ? Ben yapabiliyor diye tahmin ediyordum ancak o zaman sizin verdiğiniz örnek kodu delegate yerine function ilede çalıştırabilmemiz gerekiyor. Ancak ben çalıştıramadım.

Tamam şu halde doğru çalışıyor:
 
import std.stdio;
 
void dene(string başlık, void function() işlem)
{
 
    writeln(başlık, ':');
    write("  ");
    işlem();
    writeln();
        
}
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
void main()
{
    dene("indeks ile", function(){
        
            for (int i = 0; i != dizgi.length; ++i) {
                write(dizgi[i], ' ');
            }
        });
 
    dene("foreach, tür belirtmeden", function(){
            foreach (harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, char ile", function(){
            foreach (char harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}

Ancak şu halde de doğru çalışmasını bekliyordum :

import std.stdio;
 
void dene(string başlık, void function() işlem)
{
 
    writeln(başlık, ':');
    write("  ");
    işlem();
    writeln();
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
}
 
void main()
{
    dene("indeks ile", function(){
        
            for (int i = 0; i != dizgi.length; ++i) {
                write(dizgi[i], ' ');
            }
        });
 
    dene("foreach, tür belirtmeden", function(){
            foreach (harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, char ile", function(){
            foreach (char harf; dizgi) {
                write(harf, ' ');
            }
        });
 
    dene("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}
acehreli (Moderatör) #5
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ı
canalpay:
Bu arada function yerel işlevde değilde o yerel işlevi kapsayacak değişken ile işlem yapabiliyor mu ?

function, yalnızca işlevin gövdesi gibi düşünülebilir. Oluşturulduğu ortama bağlılığı bulunmuyor.

Tamam şu halde doğru çalışıyor:
 
import std.stdio;
 
void dene(string başlık, void function() işlem)
{
 
    writeln(başlık, ':');
    write("  ");
    işlem();
    writeln();
        
}
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
void main()
{
// ... Ali kırptı ...
 
    dene("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}

Tabii onun çalışmasının nedeni, dizgi'nin artık evrensel olması ve function oluşturulduğunda onun anlaşılması. Yani derleyici için bütün bilgi mevcut.

Ancak şu halde de doğru çalışmasını bekliyordum :

import std.stdio;
 
void dene(string başlık, void function() işlem)
{
 
    writeln(başlık, ':');
    write("  ");
    işlem();
    writeln();
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
}
 
void main()
{
// ... Ali kırptı ...
 
    dene("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}

Orada son foreach satırı derlenemiyor çünkü derleyici foreach'teki dizgi'nin ne olduğunu bilemez.

Bunun nedeni, derleyici kodu bütünüyle irdelemez veya irdeleyemez. Orada ne olduğu bilinmeyen bir "dizgi" var. Ne o kapsamda bildirilmiş, ne de evrensel alanda. Derleyici o yüzden hata veriyor. Daha ileriye giderek onun gönderildiği işlevin içini de okuyarak oradaki "dizgi"nin kastedildiğine karar vermez.

Şöyle düşünelim:

if (bir_koşul) {
    dene("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
} else {
    dene_2("foreach, dchar ile"function(){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });}}}
}

Ya dene_2 işlevi içinde "dizgi" diye bir şey tanımlı değilse? Derleyici hata vermeli mi? Ya bir_koşul her zaman için true olacaksa? O zaman aslında hata olmamalı. vs. vs. Bu irdelemenin sonu yoktur.

O yüzden derleyici fazla derinine düşünmez ve zaten bazı durumlarda düşünemez.

Ortalığı karıştırmak için bir tane de benden: :)

import std.stdio;
 
void dene(string başlık, const char[] dizgi, void function(const char[]) işlem)
{
    writeln(başlık, ':');
    write("  ");
    işlem(dizgi);
    writeln();
}
void main()
{
    string dizgi = "abcçdefgğhıijklmnoöpqrsştuüvwxyz";
 
    dene("foreach, dchar ile",  dizgi, function(const char[] parametre_dizgi){
            foreach (dchar harf; parametre_dizgi) {
                write(harf, ' ');
            }
        });
}

O kodda main içindeki dizgi dene'ye gönderiliyor. dene de onu işlem'e parametre olarak veriyor.

dizgi'yi dene içinde yazmak ve işlem'e parametre olarak vermek de olabilir:

import std.stdio;
 
void dene(string başlık, void function(const char[]) işlem)
{
    writeln(başlık, ':');
    write("  ");
    işlem("abcçdefgğhıijklmnoöpqrsştuüvwxyz");
    writeln();
}
void main()
{
    dene("foreach, dchar ile", function(const char[] dizgi){
            foreach (dchar harf; dizgi) {
                write(harf, ' ');
            }
        });
}

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:
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, 03:00:49 (UTC -08:00)