Tek bir string tipi, ama iki farklı kullanım şekli

TROIA, Java ya da C#'ın aksine karakter ve string için ayrı tipler tutmuyor — hepsi STRING. Ne string'lerin ne de sabit metinlerin (hardcoded string) sabit bir maksimum uzunluğu var. Ama bu basitliğin altında, özellikle birleştirme (concatenation) söz konusu olduğunda dikkat edilmesi gereken önemli bir performans farkı saklı: STRING ile + operatörü mü, yoksa STRINGBUILDER ile APPENDSTRING mi?

Kaçış karakteri yok, TOCHAR() var

Çoğu dilde tek tırnak içinde tek tırnak kullanmak için \' gibi bir kaçış dizisi yazarsınız. TROIA'da kaçış dizisi kavramı yok; bunun yerine ASCII ondalık değerinden karakter üreten TOCHAR() fonksiyonu kullanılıyor:

STRVAR = 'Bu satır ' + TOCHAR(39) + ' (tek tırnak) içeriyor.';

TOCHAR(10) bir satır sonu (newline) üretir — bir dosyaya ya da mesaja elle satır sonu eklemeniz gerektiğinde bu fonksiyon işinize yarar.

Temel string fonksiyonları

Fonksiyon Ne yapar
STRLEN String uzunluğunu döner
STRPOS() Bir string'in başka bir string içindeki konumunu bulur
ISNUMERIC() Tüm karakterlerin sayısal olup olmadığını kontrol eder
STRLIKE() SQL LIKE operatörüne benzer desen karşılaştırması yapar
TRIM() Baştaki/sondaki boşlukları temizler
REPLACE() Bir alt string'i başka biriyle değiştirir
STRSTR() İndeks ve uzunluğa göre alt string döner
BASE64ENCODE() / BASE64DECODE() Binary-metin dönüşümü (encoding belirtmek gerekir, örn. UTF-8)
GETDIGEST() MD5, SHA1 gibi algoritmalarla hash üretir

+ operatörünün gizli maliyeti

SONUC = SONUC + SATIR + TOCHAR(10);

Bu satır tek başına zararsız görünür — ama bir döngü içinde binlerce kez çalışırsa, her + işleminde arka planda yeni bir string nesnesi oluşturulur ve öncekinin tamamı kopyalanır. 100 satırlık bir birleştirmede fark edilmez; 50.000 satırlık bir raporda application server'ı gözle görülür şekilde yavaşlatır.

STRINGBUILDER: aynı iş, farklı maliyet eğrisi

LOCAL:
    STRINGBUILDER SB;
    TABLE VERI(SATIR CHAR(200));

LOOP AT VERI
BEGIN
    SB APPENDSTRING VERI_SATIR;
    SB APPENDSTRING TOCHAR(10);
ENDLOOP;

SONUCMETNI = SB;

Önemli sınır: STRINGBUILDER'ı her string işlemi için STRING'in yerine koymaya çalışmayın — belgeler bunun sadece birleştirme senaryoları için tasarlandığını, genel string işlemleri için STRING'in yerini almadığını açıkça belirtiyor. Yani bir STRINGBUILDER üzerinde STRPOS() ya da REPLACE() gibi fonksiyonları çağırmadan önce genelde onu tekrar STRING'e çevirmeniz gerekir.

PARSE ile string üzerinde gezinmek

PARSE {anastring} INTO {token} [DELIMITER {ayirici}]
BEGIN
    {blok}
ENDPARSE;

Ayırıcı belirtilmezse satır sonlarına göre böler. BREAK ve CONTINUE, tıpkı WHILE/LOOP AT'te olduğu gibi PARSE içinde de çalışıyor — yani belirli bir token'a ulaşınca ayrıştırmayı erken durdurabilirsiniz.

Gerçek bir örnek: CSV satırını ayrıştırıp toplam hesaplamak

/* Noktalı virgülle ayrılmış bir tutar listesini toplar. */
LOCAL:
    STRING TOKEN;
    DECIMAL TOPLAM;

TOPLAM = 0;

PARSE '150.50;200.00;89.90;300.00' INTO TOKEN DELIMITER ';'
BEGIN
    IF ISNUMERIC(TOKEN) == 0 THEN
        CONTINUE;
    ENDIF;
    TOPLAM = TOPLAM + TOKEN;
ENDPARSE;

Sık yapılan hatalar

  • Büyük döngülerde + ile birleştirmeye devam etmek — özellikle rapor/export üreten kodlarda bu, en kolay gözden kaçan ama en somut ölçülebilir performans kazanımlarından biri; STRINGBUILDER'a geçmek genelde tek satırlık bir değişiklik.
  • STRINGBUILDER üzerinde doğrudan STRPOS/REPLACE gibi fonksiyonlar çağırmaya çalışmak — bu tip genel string işlemleri için tasarlanmadı; önce STRING'e çevirmeniz gerekiyor.
  • Kaçış karakteri arayıp bulamamak — bir string literalinin içine tek tırnak koymaya çalışırken \' yazıp derleme hatası almak; doğru yol TOCHAR(39).
  • BASE64ENCODE/DECODE'da encoding belirtmemek — Türkçe karakter içeren metinlerde encoding uyuşmazlığı, dosya işlemlerinde bahsettiğim CODEPAGE sorununun bir başka versiyonu olarak karşınıza çıkar.
  • PARSE'ta DELIMITER vermeyi unutup, satır sonu beklediğini fark etmemek — tek satırlık bir string'i ayırıcıyla bölmek isterken DELIMITER parametresini atlarsanız, PARSE tüm string'i tek bir token olarak işler.

Sıradaki adım

Bir sonraki yazıda, tekrar eden alan tanımlarını merkezi olarak yönetmenin yolu olan Domain kavramına değineceğim.