Thread overview
string'in bir parçasını (sub-string) almak
Oct 28, 2013
Salih Dinçer
Oct 28, 2013
Salih Dinçer
Oct 28, 2013
Salih Dinçer
Oct 28, 2013
Salih Dinçer
October 26, 2013

Başka dillerde bulunan substr() gibi işlevler Phobos'ta bulunmuyor. D'de dilimlemek var ama tabii string'in UTF-8 dizisi olduğunu hatırlarsak işe yaramadığı açık.

Örneğin, şöyle bir kullanım iyi olurdu:

   // İkinci indeksten dördüncü indekse kadar (dört hariç)
   assert("abcçdef".subString(2, 4).equal("cç"));

İlk parametre başlangıç indeksi olabilir. İkinci indeks ise ya uzunluk olur ya da yukarıda olduğu gibi bitiş indeksi.

Bu soru şu sıralarda İngilizce D.learn haber grubunda da soruldu. (Oradan kopya çekmeyin! :-p) Orada eksi değerli indekslerin de kullanışlı olacağı hatırlatıldı. Başka dillerde öyle: -1 indeksi sonuncu karakter anlamına geliyor; -2 sondan bir önceki karakter, vs.

Siz olsanız nasıl yazardınız?

Ali

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

October 28, 2013

Kötü bir kodlama oldu ama benim bulduğum çözüm şu:

import core.bitop : popcnt;

string subString(string str, size_t left, size_t right) {
 debug(0) {
   foreach(chr; str) chr.write(", ");
   writeln;
 }

 int chrCount, bitPos = 8;

 size_t[] xSay;
 string result;

 foreach(chr; str) {
   while(bitPos--) {
     auto bitTest = 8 - popcnt(chr >> bitPos);
     if(bitTest == bitPos) {
       chrCount++;
     } else {
       bitPos = 0; // break ?
     }
   }

   if(chrCount && !result.length) xSay ~= chrCount;

   if(chrCount--) {
     if(result.length) {
       assert(popcnt(chr >> 6) == 1, "UTF failure");
     }
     result ~= chr;
   } else {
     debug(0) chr.write;
     xSay ~= 1;
   }
   if(chrCount < 1) {
     debug(0) result.write;
     bitPos = 8;
     result.length = 0;
     chrCount = 0;
   }
 }

 debug(0) xSay.writeln;

 if(right > xSay.length) {
   assert(0, "Range violationnnn"); // customizable
 }

 size_t a, b;
 foreach(sum; xSay[0..left]) a += sum;
 foreach(sum; xSay[left..right]) b += sum;

 return str[a..a+b];
}


import std.stdio, std.algorithm : equal;

void main() {
assert("abcçdef".subString(2, 4).equal("cç"));
assert("abcÇçuüz".subString(3, 5).equal("Çç")); // chr.length == 8

debug(1) "ağ".subString(0, 3).writeln; // range violation error
}

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

October 28, 2013

Hocam seninki çok daha leziz ve inanılmaz kısa olmuş...:)

Bahsettiklerin dışında bir farkı da "range violation" hatası vermemesi. Çünkü aralıklar üzerinde çalışıyor. Tabi subString() içinde uzunluk denetimi yapabilmemiz mümkün ama "abcçdef".subRange(2, 40) diye bir parametre verdiğimizde hiç bir hata atmadan olduğu gibi sonuna kadar aralık döndürüyor.

Biraz zor bir örnek (UTF8+UTF16+UTF8) üzerinde test ettiğimde, her ikisinde de bir sorun yaşamadım.
(Editörünüz, aşağıdaki satırı sağa bitişik ve garip şekilde "';subRange(0, 2).writeln."ߡࠀߜ"'" yazabilir!)

"ߡࠀߜ".subRange(0, 2).writeln; //ࠀߜ

/* Benim çıktı:
�, �, �, �, �, �, �,
ߡࠀߜ[2, 3, 2]
*/

Yazdıklarımızı biraz daha geliştirip (range ve low level birleştirilerek) bir sınıf haline getirmemiz mümkün. Belki o zaman çeşitli özellikler eklenebilir. Örneğin index'i verilen karakterin hafızada kaç byte yer kapladığı olabilir. Tıpkı yukarıdaki örnekte, ortadaki karakterin 3 byte yer kaplaması gibi.

Özetle kodunuz aralık isterse kısa kodun gönderdiğini, dizi isterse benim yazdığımın sonucunu gönderebilir. Bilmiyorum yurt dışında ne tür çözümler geldi ama açıkcası hiç bakmadım. Tabii ki her yiğidin yoğurt yiyişi farklı ama ben biraz bit'ler üzerinde cirit atmayı, Ali hocam da aralıklarda gezinmeyi sanırım çok seviyor...:)

Sevgiler, saygılar...

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

October 28, 2013

Yaptığım kodlama içerisine açıklama yerleştirme fırsatım olmadı. Öylesine ayaküstü yazılmış bir şeydi. Aslında bitler içindeki düzeni ben de bilmiyordum. Internette bir çok kaynakta codepoint'den bahsediliyordu.
(-bknz. http://en.wikipedia.org/wiki/UTF-8#Description)

Gerçekten basit bir sistem olduğu için fazla açıklama yapmıyorum. Hatta yazdığımdan daha akıllıcası ve kısası mümkün de olabilir. Az önce koda bakarken abartılmış if()'ler gördüm. Sanırım bunları kaynaştırmak mümkün. Wikipedia maddesi ile döngü çekirdeğine bakarsanız ne yapmak istediğimi çıkarabilirsiniz. Aslında her şey bakkal hesabı gibi saymaktan ibaret...:)

Başarılar...

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

October 28, 2013
import core.bitop : popcnt;

Son olarak popcnt()'nin ne yaptığı hakkında bilgi vereyim...

Bir keresinde şuradaki başlıkta (http://ddili.org/forum/thread/1109), çekirdeğin bir modülünden yorumsuz bir şekilde bahsetmiştim. Aslında içeriğinde başka işlevler de var ama Wikipedia maddesini görünce aklıma hemen o işlev geldi. Ben de kodu onun üzerine bina ettim.

Belki kendi maskelememizi yapabilirdik ama bu, gelişmiş CPU'lar için çok hızlı sonuç üretecek şekil tasarlanmış bir modüldü ve ortalığı daha fazla karıştırmamayı yeğledim...:)

İşleve gelince; tek yaptığı kendisine gönderilen uint değerin kaç adet 1 bitine sahip olduğunu bizim için saymak. Zaten UTF'de ilk baytın solunda kaç tane bitişik 1 var ise bize bu karakterin kaç byte'dan oluştuğu bilgisini veriyor. Ama işlem biraz daha kontrollü olması için baytı sırayla (belki gereksizce) solda saymaya çalıştım.

Mutlaka daha basit yöntemi de vardır, ne dersiniz?

Dip Not: Şurada (http://www.czyborra.com/utf/) bazı C kodları gördüm. İşimize yarayabilirdi de...

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

October 28, 2013

Seninkinin iyi tarafı, döndürülen dilimin asıl karakterleri gösteriyor olması. (İstesek onları değiştirebiliriz diyeceğim ama UTF-8'de bunun her durumda mümkün olmadığını biliyoruz.)

Doğrusu, beklediğimden çok alt düzey bir çözüm olmuş. :) Phobos'ta o işlemlerin hiç olmazsa bazılarını karşılayan işlevler vardır. (Yeni std.uni çok kapsamlı olarak geliyor(muş).)

Benim ilk aklıma gelen yöntem çok kısa ama bir kötü tarafı, seninki gibi var olan bir dilim döndürmüyor. subRange karakterleri tembel olarak üretiyor. subString ise o aralığı hevesle string'e dönüştürüyor:

import std.range;
import std.algorithm;

auto subRange(R)(R r, size_t beg, size_t end)
{
   return r.dropExactly(beg).take(end - beg);
}

unittest
{
   assert("abcçdef".subRange(2, 4).equal("cç"));
}

import std.conv;

string subString(string s, size_t beg, size_t end)
{
   return s.subRange(beg, end).text;
}

unittest
{
   assert("abcçdef".subString(2, 4).equal("cç"));
}

void main()
{}

Ali

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

October 28, 2013

Alıntı (Salih Dinçer):

>

inanılmaz kısa olmuş...:)

Çünkü D (ve Phobos) UTF-8 kodlamasını biliyor ve dropExactly dediğimde senin yaptığın işlemlerin benzerleri ile o kadar sayıda harf atlıyor.

Alıntı:

>

Bahsettiklerin dışında bir farkı da "range violation" hatası vermemesi.

O benim hatam olmuş. take yerine takeExactly kullanılırsa o da denetlenir.

Alıntı:

>

Tabi subString() içinde uzunluk denetimi yapabilmemiz mümkün

Hem de aralığın çeşidine göre... Örneğin, length niteliği varsa sonuna kadar ilerlemeden öğrenmek mümkün:

import std.range;
import std.algorithm;
import std.traits;
import std.exception;
import std.string;

auto subRange(R)(R r, size_t beg, size_t end)
{
   static if (hasLength!R || isArray!R) {
       enforce((beg < r.length) && (end <= r.length),
               format("%s elemanlı aralıkta [%s,%s) indeksleri yasal değil",
                      r.walkLength, beg, end));
   }

   return r.dropExactly(beg).takeExactly(end - beg);
}

import std.conv;

string subString(string s, size_t beg, size_t end)
{
   return s.subRange(beg, end).text;
}

void main()
{
   assert("abcçdef".subString(2, 40).equal("cç"));
}

Dizginin uzunluğu 7 yazılsın diye hata mesajında r.length değil, r.walkLength kullandım. Hata mesajı:

'7 elemanlı aralıkta [2,40) indeksleri yasal değil'

Ali

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