HotXLS, R1C1 referans notasyonunda yazılmış formülleri, R2C3 (mutlak), R[-1]C[2] (göreli ofset) ve RC (geçerli hücre) gibi biçimleri kabul eden, UAE1 notasyonuna dönüştüren ve sonucu sıradan A1 formüllerini işleyen aynı derleyiciye besleyen TXLSCalculator.GetCompiledFormulaR1C1 aracılığıyla derler. Yüzlerce satır boyunca aynı formülü üreten Delphi ve C++Builder kodları için bu yöntem, tüm dize birleştirme (string-concatenation) hatası sınıfını ortadan kaldırır
Bu hata sınıfı, programlı olarak bir sütunu doldurmuş olan herkese tanıdık gelecektir. Satırlar üzerinde dönersiniz ve her satır için Format('D%d*E%d', [Row, Row]) ile bir A1 formül dizesi oluşturursunuz. Her yineleme satır numaralarını metne ekler ve değişen tek kısım satır numaralarıdır. Ofseti bir kez yanlış ayarlayın, 0 tabanlı bir döngü sayacını 1 tabanlı A1 satır numaralarıyla karıştırın veya veri bloğunu bir başlık satırı kadar kaydırın; sütundaki her formül bir satır sonrasını gösterir. Hiçbir istisna oluşmaz; sayılar sadece yanlıştır. Aslında kastettiğiniz formül, "solumdaki iki hücreyi çarp," hiçbir şekilde satır numarasından bahsetmez ve R1C1 notasyonu bunu bu şekilde yazmanıza izin verir
R1C1 notasyonu nedir ve ne zaman kullanmalısınız?
R1C1 notasyonu, hücreleri sütun harfi artı satır numarası yerine satır ve sütun numarasıyla adresler ve göreli referansları formül hücresinden açık ofsetler olarak işaretler. R2C3, A1'in $C$2 olarak yazdığı satır 2, sütun 3'teki mutlak hücredir. R[-1]C[2], formülün oturduğu yerin bir satır yukarısı ve iki sütun sağındadır. RC, formül hücresinin kendisidir. Köşeli parantez içindeki ofsetler can alıcı noktadır: R1C1'deki göreli bir referans, hangi hücrenin onu barındırdığına bakılmaksızın aynı şekilde okunurken, aynı referansın A1 yorumu her satırla birlikte değişir
Bu notasyon, tam olarak tek bir senaryoda değerini kanıtlar ve bu yaygın bir senaryodur: Aynı göreli formülün bir veri bölgesinin her satırına yerleştirilmesi gereken şablon oluşturma (template generation). A1'de formül metnini satır başına yeniden oluşturmanız gerekir. R1C1'de ise metin bir sabittir. Bu aynı zamanda elektronik tablo dosya biçimlerinin dahili olarak nasıl düşündüğüne de daha yakındır: Paylaşılan formül kayıtları, göreli referansları ana hücreden satır ve sütun ofsetleri olarak saklar; dolayısıyla satır başına bir A1 dizesi, kodunuzun yalnızca ayrıştırıcının onu tekrar ofsetlere dönüştürmesi için sentezlediği bir şeydir. R1C1 bu gidiş-dönüşü atlar. Etkileşimli, insan tarafından yazılan formüller için A1 doğal seçim olmaya devam eder; bu nedenle HotXLS'in her yerinde varsayılan olarak kalır
HotXLS bir R1C1 formülünü nasıl derler?
HotXLS, v2.175.0'da eklenen bu özelliği iki düzeyde sunar. TXLSCalculator.GetCompiledFormulaR1C1(UncompiledFormula: String; SheetID, CurRow, CurCol: Integer): TXLSCompiledFormula çoğu kodun çağırdığıdır: A1 kardeşi GetCompiledFormula gibi değerlendirmeye hazır derlenmiş bir formül döndürür, ancak formülün ait olduğu hücrenin 0 tabanlı satır ve sütununu adlandıran iki ekstra parametreye sahiptir. Altında, TXLSFormula.GetCompiledR1C1 ham sözdizimi ağacını üretir ve bağımsız bir işlev olan R1C1ToA1(const AFormula: String; CurRow, CurCol: Integer): String gerçek notasyon dönüşümünü gerçekleştirir. Süreç hattı kasıtlı olarak basittir: R1C1 metnini ana hücre koordinatlarını kullanarak eşdeğer A1 metnine dönüştürün, ardından A1 metnini mevcut motor aracılığıyla derleyin — tanımlanmış adları ve sayfalar arası referansları çözümleyen ve özel çalışma sayfası işlevlerini dağıtan aynı motor
Dönüşüm derlemeden önce gerçekleştiğinden, aşağı akıştaki her şey A1 formülünü kendiniz yazmışsınız gibi davranır. R1C1ToA1('R2C3', 4, 3), her iki koordinat da mutlak olduğundan, ana hücreden bağımsız olarak '$C$2' döndürür. CurRow = 4 ve CurCol = 3 0 tabanlı olduğundan D5'te yaşayan bir formül olan R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3), 'SUM(D2:D4)' döndürür: Ofsetler satır 5, sütun D'ye göre çözümlenmiş ve düz göreli A1 referansları olarak yayılmıştır. Aralıklar için özel bir duruma gerek yoktur; iki nokta üst üste işareti geçer ve her uç nokta bağımsız olarak dönüştürülür
// Formül D5'te yaşıyor: CurRow = 4, CurCol = 3 (her ikisi de 0 tabanlı)
S := R1C1ToA1('R2C3', 4, 3);
// S = '$C$2' (mutlak satır ve sütun)
S := R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3);
// S = 'SUM(D2:D4)' (ofsetler D5'e göre çözümlendi)
S := R1C1ToA1('ROUND(R[-1]C[0], 2)', 4, 3);
// S = 'ROUND(D4, 2)' (ROUND içindeki R harfine dokunulmadı)
Bir sütunu tek bir göreli formülle doldurma
Kazanç döngüde kendini gösterir. Her yinelemede formül metnini yeniden oluşturan A1 sürümü ile formülün bir sabit olduğu ve yalnızca ana koordinatların hareket ettiği R1C1 sürümünü karşılaştırın. Her ikisi de TXLSCalculator aracılığıyla derlenir ve GetValue ile değerlendirilir; hesaplayıcı oluşturulurken bir hücre sağlayıcı geri araması (cell-provider callback) alır, böylece değerlendirici veri kaynağınızdan hücre değerlerini çekebilir
// A1 stili: her satır için farklı bir formül dizesi
for Row := 1 to 500 do
begin
FormulaText := Format('D%d*E%d', [Row + 1, Row + 1]); // 1 tabanlı A1 satırları
Compiled := Calc.GetCompiledFormula(FormulaText, 0);
// ... değerlendir, sakla, serbest bırak ...
end;
const
AmountFormula = 'RC[-2]*RC[-1]'; // iki hücre solda, aynı satırda
var
Calc: TXLSCalculator;
Compiled: TXLSCompiledFormula;
Value: Variant;
Row: Integer;
begin
Calc := TXLSCalculator.Create(nil, Provider.GetValue);
try
for Row := 1 to 500 do
begin
Compiled := Calc.GetCompiledFormulaR1C1(AmountFormula, 0, Row, 5);
try
if Calc.GetValue(0, Compiled, Row, 5, Value, 1) = lxOk then
StoreResult(Row, 5, Value);
finally
Compiled.Free;
end;
end;
finally
Calc.Free;
end;
end;
R1C1 döngüsünün formül metninde hiçbir satır aritmetiği yoktur. 'RC[-2]*RC[-1]', satır 2'de de satır 500'de de "aynı satır, iki sütun sol, çarpı aynı satır, bir sütun sol" anlamına gelir ve veri bloğu daha sonra bir başlık satırı kadar aşağı kaysa bile formül sabiti değişmez — yalnızca döngü sınırları değişir. A1 sürümünde + 1 ayarını yanlış yapmak için iki yer vardır; R1C1 sürümünde ise sıfırdır
Dönüştürücü hangi R1C1 biçimlerini kabul eder?
R1C1ToA1 dönüştürücüsü, v2.175.0 için belgelenen biçimleri tanır: Her iki yöndeki göreli ofsetler için R[n]C[m], mutlak satır ve sütun için RnCm, negatif ofsetli R[-n]C[m], formül hücresinin kendisi için yalın RC ve R1C1:R3C3 ya da R[-1]C:R[1]C gibi aralıklar. Satır ve sütun bölümleri bağımsız olarak ayrıştırılır, bu nedenle R[1]C3 (göreli satır, mutlak sütun) gibi karışık biçimler de çalışır ve harfler büyük/küçük harfe duyarsızdır, bu nedenle r[-1]c[2] büyük harfli ikiziyle aynı şekilde derlenir. Köşeli parantezli kısımlar sabitlenmemiş (göreli) A1 koordinatları haline gelir; yalın sayılar ise $ sabitlemeli mutlak koordinatlar haline gelir
İlginç soru, dönüştürücünün formüldeki diğer her şeyi bozmaktan nasıl kaçındığıdır, çünkü R veya C yaygın harflerdir. Ayrım kuralı belirteç tabanlıdır (token-based): Bir R harfi, yalnızca önünde başka bir harf olmadığında bir referansın başlangıcı olarak kabul edilir ve ardından adayın tamamen ayrıştırılması gerekir — isteğe bağlı satır kısmı, zorunlu C, isteğe bağlı sütun kısmı — aksi takdirde metin dokunulmadan geri yüklenir. ROUND(R[-1]C[0], 2) işlevinin yalnızca iç referansı dönüştürmesinin nedeni budur: ROUND içindeki R harfini bir basamak, parantez veya C yerine O harfi takip eder, bu nedenle ayrıştırma başarısız olur ve işlev adı aynen geçer. Aynı mantık ROW() işlevini de korur ve C ile başlayan işlev adları hiçbir zaman aday olamaz, çünkü yalnızca R bir referansı başlatır. v2.175.0 sürüm notları, dize sabitlerinin (string literals) ve tanımlayıcıların da atlandığını belirtmektedir; yine de, formülünüzdeki tırnak içine alınmış bir sabit tam olarak R1C1 referansı şeklinde biçimlendirilmiş metin içeriyorsa, üretimde güvenmeden önce derlenmiş çıktıyı bir kez kontrol etmeye değer
Koordinat tabanları ve bilmeye değer sabitleme (anchoring) ayrıntıları
Bu API içinde iki kural karşılaşır ve bunları düz tutmak tek gerçek tuzaktan kaçınmayı sağlar. GetCompiledFormulaR1C1 işlevinin CurRow ve CurCol parametreleri, hesaplayıcı API'sini takip ederek 0 tabanlıdır; notasyonun kendisindeki sayılar ise Excel'in görüntülediğiyle eşleşecek şekilde 1 tabanlıdır: R2C3, $D$3 değil $C$2 olan satır 2, sütun 3'tür. Döngü sayacınız zaten 0 tabanlıysa bunu doğrudan CurRow olarak geçirirsiniz; + 1 kodunuzda değil dönüştürücünün içinde yaşar
Derlenen formül, derlendiği hücreden daha uzun yaşayacaksa bir ayrıntı daha önem kazanır. Bir satır veya sütun kısmını atladığınızda — RC[-1] veya R[2]C biçimleri — atlanan koordinat ana hücreye çözümlenir ve dönüştürülen A1 metninde mutlak, $ sabitli koordinat olarak yayılır. Değer her iki şekilde de aynı olduğundan, değerlendirme zamanında bu görünmezdir. Ancak göreliye karşı mutlak sabitleme, referansların daha sonra satırlar veya sütunlar eklendiğinde veya silindiğinde nasıl kayacağını belirler; bu konu formül referansı ayarlaması hakkındaki eşlik eden makalede ele alınmıştır. Yapısal düzenlemeler boyunca bir koordinatın göreli kalmasına ihtiyacınız varsa, dönüştürücünün sabitlenmemiş bir A1 referansı yayması için ofseti açıkça yazın — RC[-1] yerine R[0]C[-1]
R1C1 derlemesi, yukarıda gösterilen A1 derleyicisi, yeniden hesaplama grafiği ve değerlendirme API'sinin yanı sıra HotXLS Delphi Excel Bileşeni'ndeki formül motorunun bir parçasıdır. Kodunuz sütunlar boyunca formülleri döngüye sokarak elektronik tablolar oluşturuyorsa, bu döngüleri dize eklemeli A1'den tek bir R1C1 sabitine taşımak, mevcut en ucuz güvenilirlik yükseltmelerinden biridir