Dizgeleri Yerele Özgü Karşılaştırma İşlevleri
Önceki V. Oylum - Diziler ve Dizgeler Sonraki
Dizgeleri Yerele Özgü Karşılaştırma İşlevleri
Bazı yerellerde alfabetik sıralama karakter kodlarının sıralamasından farklıdır.[92]
strcoll, strxfrm, (string.h dosyasında bildirilmişlerdir) wcscoll ve wcsxfrm (wchar.h dosyasında bildirilmişlerdir) işlevlerini yerele özgü karakter sıralamasına uygun dizge karşılaştırmalarında kullanabilirsiniz. Bu işlevlerin kullanacağı yereli LC_COLLATE yerel kategorisine gerekli değeri atayarak belirtebilirsiniz. Daha ayrıntılı bilgi edinmek için Yereller ve Uluslararasılaştırma kısmına bakınız.
Standart C yerelinde karakter sıralaması bakımından strcoll ile strcmp işlevlerinin davranışlarında bir fark yoktur. Benzer olarak wcscoll ve wcscmp işlevleri de bu bakımdan aynıdır.
Bu işlevleri etkin olarak çalıştırmanın yolu bir dizgenin içindeki karakterleri yerelin karakter sıralamasına uygun bir konumlamayla bir bayt sıralamasına dönüştürmektir. Böyle oluşturulmuş bayt sıralamaları ile yerelin karakter sıralamasına uygun olarak dizgeleri karşılaştırmak artık kolaydır.
strcoll ve wcscoll işlevleri bu dönüşümü karşılaştırma sırasından dolaylı olarak uygularlar. strxfrm ve wcsxfrm işlevleri ise tam aksine doğrudan doğruya karakter sıralaması/alfabetik sıralama eşleştirmesi yaparlar. Bir dizge kümesi üzerinde çok sayıda karşılaştırma yapacaksanız önce strxfrm veya wcsxfrm işlevlerini kullararak dizgeleri bir kerede dönüştürüp ardından strcmp veya wcscmp ile dönüştürülmüş dizgeleri karşılaştırmak daha verimli bir yöntemdir.
int strcoll
(const char *s1,
 const char *s2)
işlev
Bu işlev, karakter sıralaması için yerelin (LC_COLLATE yereli) karakter sıralamasını kullanması dışında strcmp işlevine benzer.
int wcscoll
(const wchar_t *ws1,
 const wchar_t *ws2)
işlev
Bu işlev, karakter sıralaması için yerelin (LC_COLLATE yereli) karakter sıralamasını kullanması dışında wcscmp işlevine benzer.
Aşağıdaki örnekte bir dizge dizisi strcoll ile karşılaştırılarak sıralanmaktadır. Burada gerçek sıralama algoritması yazılmamıştır; bunun için qsort (Dizi Sıralama İşlevi) kullanılmıştır. Buradaki kodun yaptığı iş dizgeler sıralanırken nasıl karşılaştırılacağını göstermektir. (Bu bölümün devamında strxfrm kullanarak bunun daha verimli olarak nasıl yapılacağından bahsedilecektir.)
/* Bu, qsort ile kullanılan bir karşılaştırma işlevidir. */

int
elemanlari_karsilastir (char **p1, char **p2)
{
  return strcoll (*p1, *p2);
}

/* Burası giriş noktası---yerelin karakter sıralaması
   kullanılarak dizgeleri sıralayan işlev. */

void
sort_strings (char **dizi, int dizge_sayisi)
{
  /* Dizgeleri karşılaştırarak diziyi sırala. */
  qsort (dizi, dizge_sayisi,
         sizeof (char *), elemanlari_karsilastir);
}
size_t strxfrm
(char *restrict       hedef,
 const char *restrict kaynak,
 size_t               boyut)
işlev
strxfrm işlevi, harf sıralaması için seçilmiş olan yerele göre saptanan karakter dönüşümünü kullanarak kaynak dizgesini dönüştürür ve dönüştürülen boyut karakterlik dizgeyi (sonlandırıcı boş karakter dahil) hedef dizisine kaydeder.
hedef ve kaynak birbirini eziyorsa işlevin davranışı tanımsızdır. Daha fazla bilgi için Kopyalama ve Birleştirme bölümüne bakınız.
Dönen değer dönüştürülen dizgenin uzunluğudur. Bu değer boyut değerinden etkilenmez, ancak boyut'tan büyük ya da eşitse, dönüştürülen dizge hedef dizisine sığmamış demektir. Bu durumda, diziye sığdığı kadarıyla dizge kaydedilmiştir. Dönüştürülen dizgenin tamamını almak için işlevi daha büyük bir dizi ile tekrar çağırmalısınız.
Dönüştürülmüş dizge verilen dizgeden daha uzun olabileceği gibi daha kısa da olabilir.
boyut sıfırsa, hedef dizisine herhangi bir değer kaydedilmez. Bu durumda, strxfrm işlevi sadece dönüştürülmüş dizgenin uzunluğu ile döner. Bu ayrılacak dizinin boyunun ne olacağını saptamak açısından yararlıdır. boyut sıfır olduğunda hedef'in önemi yoktur, bir boş dizge bile olabilir.
size_t wcsxfrm
(wchar_t *restrict hedef-geniş,
 const wchar_t    *kaynak-geniş,
 size_t            boyut)
işlev
wcsxfrm işlevi, harf sıralaması için seçilmiş olan yerele göre saptanan karakter dönüşümünü kullanarak kaynak-geniş dizgesini dönüştürür ve dönüştürülen boyut geniş karakterlik dizgeyi (sonlandırıcı boş karakter dahil) hedef-geniş dizisine kaydeder.
hedef-geniş ve kaynak-geniş birbirini eziyorsa işlevin davranışı tanımsızdır. Daha fazla bilgi için Kopyalama ve Birleştirme bölümüne bakınız.
Dönen değer dönüştürülen deniş karakterli dizgenin uzunluğudur. Bu değer boyut değerinden etkilenmez, ancak boyut'tan büyük ya da eşitse, dönüştürülen geniş karakterli dizge hedef-geniş dizisine sığmamış demektir. Bu durumda, geniş karakterli dizge, diziye sığdığı kadarıyla kaydedilmiştir. Dönüştürülen geniş karakterli dizgenin tamamını almak için işlevi daha büyük bir dizi ile tekrar çağırmalısınız.
Dönüştürülmüş geniş karakterli dizge verilen geniş karakterli dizgeden daha uzun olabileceği gibi daha kısa da olabilir.
boyut sıfırsa, hedef-geniş dizisine herhangi bir değer kaydedilmez. Bu durumda, wcsxfrm işlevi sadece dönüştürülmüş geniş karakterli dizgenin uzunluğu ile döner. Bu ayrılacak dizinin boyunun ne olacağını saptamak açısından yararlıdır (değeri sizeof (wchar_t) ile çarpmayı unutmayın). boyut sıfır olduğunda hedef-geniş'in önemi yoktur, bir boş dizge bile olabilir.
Buradaki örnekte, çok sayıda karşılaştırma yapmayı planladığınızda strxfrm işlevini nasıl kullanacağınız gösterilmiştir. Önceki örnekle aynı şeyi yapsa da daha hızlıdır, çünkü her dizgeye sadece bir kere dönüşüm uygular, diğer dizgelerle kaç defa karşılaştırma yapıldığının önemi yoktur. Çok sayıda dizge olduğunda kazanılan zaman, bellek ayırmak ve serbest bırakmak için harcanan zamandan bile daha büyüktür.
struct siralayici { char *girdi; char *donusmus; };

/* Bu karşılaştırma işlevi, struct siralayici
   dizisini sıralamak için qsort ile birlikte
   kullanılmıştır. */

int
elemanlari_karsilastir (struct sorter *p1, struct sorter *p2)
{
  return strcmp (p1->donusmus, p2->donusmus);
}

/* Burası giriş noktası---yerelin karakter sıralaması
   kullanılarak dizgeleri sıralayan işlev. */

void
dizgeleri_hizli_sirala (char **dizi, int dizge_sayisi)
{
  struct siralayici gecici_dizi[dizge_sayisi];
  int i;

  /* gecici_diziyi ilklendirelim.
     Her eleman bir girdi dizgesi ve onun dönüştürülmüşünü
     içersin. */
  for (i = 0; i < dizge_sayisi; i++)
    {
      size_t uzunluk = strlen (dizi[i]) * 2;
      char *donusmus;
      size_t donusmus_uzunluk;

      gecici_dizi[i].girdi = dizi[i];

      /* Yeterince büyük bir tamponla önce deneyelim.  */
      donusmus = (char *) xmalloc (uzunluk);

      /* dizi[i]'yi dönüştürelim.  */
      donusmus_uzunluk = strxfrm (donusmus, dizi[i], uzunluk);

      /* Tampon yetersizse yeniden boyutlandırıp tekrar deneyelim.  */
      if (donusmus_uzunluk <= uzunluk)
        {
          /* Gerekli alanı ayıralım. sonlandırıcı boş karakter
             için +1'i unutmayalım.  */
          donusmus = (char *) xrealloc (donusmus,
                                        donusmus_uzunluk + 1);

          /* Dönen değerin önemi yok çünkü dönüşmüş dizgenin
             uzunluğunu biliyoruz.  */
          (void) strxfrm (donusmus, dizi[i],
                          donusmus_uzunluk + 1);
        }

      gecici_dizi[i].donusmus = donusmus;
    }

  /* Dönüştürülmüş dizgeleri karşılaştırarak gecici_dizi diziyi sıralayalım. */
  qsort (gecici_dizi, sizeof (struct siralayici),
         dizge_sayisi, elemanlari_karsilastir);

  /* Elemanları geri, geçici diziye sıralı olarak yerleştirelim. */
  for (i = 0; i < dizge_sayisi; i++)
    dizi[i] = gecici_dizi[i].girdi;

  /* Ayrılan dizgeleri serbest bırakalım. */
  for (i = 0; i < dizge_sayisi; i++)
    free (gecici_dizi[i].donusmus);
}
Bu kodun geniş karakterli sürümünü ilgilendiren parçası şöyle olurdu:
void
dizgeleri_hizli_sirala (wchar_t **dizi, int dizge_sayisi)
{
  …
      /* dizi[i]'yi dönüştürelim.  */
      donusmus_uzunluk = wcsxfrm (donusmus, dizi[i], uzunluk);

      /* Tampon yetersizse yeniden boyutlandırıp tekrar deneyelim.  */
      if (donusmus_uzunluk <= uzunluk)
        {
          /* Gerekli alanı ayıralım. sonlandırıcı boş karakter
             için +1'i unutmayalım.  */
          donusmus = (wchar_t *) xrealloc (donusmus,
                                              (donusmus_uzunluk + 1)
                                              * sizeof (wchar_t));

          /* Dönen değerin önemi yok çünkü dönüşmüş dizgenin
             uzunluğunu biliyoruz.  */
          (void) wcsxfrm (donusmus, dizi[i],
                          donusmus_uzunluk + 1);
        }
  …
realloc çağrısındaki ek olarak yapılan sizeof (wchar_t) ile çarpma işlemine dikkat edin.
Uyumluluk Bilgisi
Dizgelerin yerele özgü harf sıralama işlevleri ISO C90'nın yeni bir özelliğidir. Daha eski C oluşumlarında buna eşdeğer bir özellik yoktur. Geniş karakteri sürümü ise ISO C90'nın 1. düzeltmesinde yer almıştır.


[92] Ç.N. - Örneğin, Türkçedeki I ve İ harfleri gibi, I harfinin karakter numarası U+0049 iken İ harfininki U+0130 J hafinin karakter kodu ise U+004A'dır. Yani IİJ alfabetik sıralaması ile U+0049, U+0130, U+004A karakter kodu sıralaması farklıdır. O kadar ki, bazı karakterlerimizi sırf karakter kodlamasına göre sıralasaydık, sıralamada sona kalacaklardır ki bu sorunlar geçmişte yazılımcıları çok uğraştırmıştı. GNU C kütüphanesi bu sorunları kökten çözmüştür.
Önceki Üst Ana Başlık Sonraki
Dizi/Dizge Karşılaştırması Başlangıç Arama İşlevleri
Bir Linux Kitaplığı Sayfası