HotXLS kompajlira formule napisane u R1C1 notaciji referenci pomoću metode TXLSCalculator.GetCompiledFormulaR1C1, koja prihvata oblike kao što su R2C3 (apsolutna), R[-1]C[2] (relativni pomak) i RC (trenutna ćelija), konvertuje ih u A1 notaciju u odnosu na red i kolonu ćelije u kojoj se formula nalazi, i prosleđuje rezultat istom kompajleru koji rukuje običnim A1 formulama. Za Delphi i C++Builder kod koji generiše istu formulu u stotinama redova, ova jedna metoda u potpunosti eliminiše čitavu klasu grešaka pri spajanju stringova
Ova klasa grešaka je poznata svima koji su programski popunjavali kolonu. Prolazite kroz redove u petlji i za svaki red gradite string A1 formule pomoću Format('D%d*E%d', [Row, Row]). Svaka iteracija ubacuje brojeve redova u tekst, a brojevi redova su jedini deo koji se menja. Ako samo jednom pogrešite u pomaku, pomešate brojač petlje koji počinje od 0 sa A1 brojevima redova koji počinju od 1, ili pomerite blok podataka za red zaglavlja, svaka formula u koloni će ukazivati na red pored. Ništa ne prijavljuje grešku; brojevi su jednostavno pogrešni. Formula koju ste zapravo želeli — "pomnoži dve ćelije sa moje leve strane" — uopšte ne pominje broj reda, a notacija R1C1 vam omogućava da je zapišete upravo tako
Šta je R1C1 notacija i kada je treba koristiti?
Notacija R1C1 adresira ćelije po broju reda i kolone umesto po slovu kolone plus broju reda, i označava relativne reference kao eksplicitne pomake od ćelije sa formulom. Oznaka R2C3 predstavlja apsolutnu ćeliju u 2. redu, 3. koloni, što A1 piše kao $C$2. Oznaka R[-1]C[2] je jedan red iznad i dve kolone desno od mesta na kojem se formula nalazi. Oznaka RC je sama ćelija sa formulom. Pomaci u zagradama su ključni: relativna referenca u R1C1 glasi isto bez obzira na to koja ćelija je sadrži, dok se A1 prikaz te iste reference menja sa svakim redom
Ova notacija opravdava svoje postojanje u tačno jednom scenariju, ali on je čest: generisanje šablona, gde se ista relativna formula mora postaviti u svaki red oblasti sa podacima. U notaciji A1 morate ponovo generisati tekst formule za svaki red. U notaciji R1C1 taj tekst je konstanta. Ovo je takođe bliže načinu na koji formati tabelarnih fajlova razmišljaju interno: zapisi deljenih formula čuvaju relativne reference kao pomake redova i kolona od ćelije domaćina, tako da je A1 string po redu nešto što vaš kod sintetiše samo da bi ga parser ponovo rastavio na pomake. R1C1 preskače taj krug. Za interaktivne formule koje pišu ljudi, A1 ostaje prirodan izbor, zbog čega je i dalje podrazumevan svuda u HotXLS-u
Kako HotXLS kompajlira formulu R1C1?
HotXLS izlaže ovu funkcionalnost na dva nivoa, počevši od verzije v2.175.0. Metoda TXLSCalculator.GetCompiledFormulaR1C1(UncompiledFormula: String; SheetID, CurRow, CurCol: Integer): TXLSCompiledFormula je ona koju većina koda poziva: ona vraća kompajliranu formulu spremnu za evaluaciju, baš kao i srodna A1 metoda GetCompiledFormula, ali sa dva dodatna parametra koji definišu indeks reda i kolone (od 0) ćelije kojoj formula pripada. Ispod nje, TXLSFormula.GetCompiledR1C1 proizvodi sirovo stablo sintakse, a samostalna funkcija R1C1ToA1(const AFormula: String; CurRow, CurCol: Integer): String vrši stvarnu konverziju notacije. Izlaz je namerno jednostavan: prevodi R1C1 tekst u ekvivalentan A1 tekst koristeći koordinate ćelije domaćina, a zatim kompajlira A1 tekst kroz postojeći mehanizam — isti mehanizam koji razrešava definisana imena i međulistne reference i otprema prilagođene funkcije radnog lista
Pošto se konverzija dešava pre kompajliranja, sve što sledi se ponaša kao da ste sami napisali A1 formulu. Poziv R1C1ToA1('R2C3', 4, 3) vraća '$C$2' bez obzira na ćeliju domaćina, jer su obe koordinate apsolutne. Poziv R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3) — formula koja se nalazi u D5, jer su CurRow = 4 i CurCol = 3 indeksirani od nule — vraća 'SUM(D2:D4)': pomaci su razrešeni u odnosu na red 5, kolonu D, i emitovani kao obične relativne A1 reference. Za opsege nije potrebno posebno rukovanje; dvotačka se propušta i svaka krajnja tačka se konvertuje nezavisno
// The formula lives in D5: CurRow = 4, CurCol = 3 (both 0-based)
S := R1C1ToA1('R2C3', 4, 3);
// S = '$C$2' (absolute row and column)
S := R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3);
// S = 'SUM(D2:D4)' (offsets resolved against D5)
S := R1C1ToA1('ROUND(R[-1]C[0], 2)', 4, 3);
// S = 'ROUND(D4, 2)' (the R in ROUND is left alone)
Popunjavanje kolone jednom relativnom formulom
Dobitak se vidi u petlji. Uporedite verziju A1, koja ponovo generiše tekst formule u svakoj iteraciji, sa verzijom R1C1, gde je formula konstanta a pomeraju se samo koordinate domaćina. Obe se kompajliraju kroz TXLSCalculator i evaluiraju pomoću GetValue; kalkulator pri kreiranju prima povratni poziv provajdera ćelija (cell-provider callback) kako bi evaluator mogao da povuče vrednosti ćelija iz vašeg izvora podataka
// A1 style: a different formula string for every row
for Row := 1 to 500 do
begin
FormulaText := Format('D%d*E%d', [Row + 1, Row + 1]); // 1-based A1 rows
Compiled := Calc.GetCompiledFormula(FormulaText, 0);
// ... evaluate, store, free ...
end;
const
AmountFormula = 'RC[-2]*RC[-1]'; // two cells to the left, same row
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;
Petlja R1C1 uopšte ne sadrži aritmetiku redova u tekstu formule. Oznaka 'RC[-2]*RC[-1]' znači "isti red, dve kolone levo, pomnoženo sa istim redom, jedna kolona levo" kako u redu 2 tako i u redu 500, a ako se blok podataka kasnije pomeri nadole za red zaglavlja, konstanta formule se ne menja — menjaju se samo granice petlje. Verzija A1 ima dva mesta na kojima možete pogrešiti u prilagođavanju + 1; verzija R1C1 ima nula
Koje oblike R1C1 konvertor prihvata?
Konvertor R1C1ToA1 prepoznaje oblike dokumentovane za verziju v2.175.0: R[n]C[m] za relativne pomake u bilo kom smeru, RnCm za apsolutni red i kolonu, R[-n]C[m] sa negativnim pomacima, čisto RC za samu ćeliju sa formulom, kao i opsege kao što su R1C1:R3C3 ili R[-1]C:R[1]C. Delovi za red i kolonu se analiziraju nezavisno, tako da rade i mešoviti oblici kao što je R[1]C3 — relativni red, apsolutna kolona, a slova ne razlikuju velika i mala, pa se r[-1]c[2] kompajlira isto kao i njegova verzija sa velikim slovima. Delovi u zagradama postaju nefiksirane (relativne) A1 koordinate; sami brojevi postaju apsolutne koordinate fiksirane znakom $
Zanimljivo pitanje je kako konvertor izbegava kvarenje svega ostalog u formuli, pošto su R i C česta slova. Njegovo pravilo razlikovanja je zasnovano na tokenima: slovo R se smatra početkom reference samo kada ispred njega ne stoji drugo slovo, a kandidat se zatim mora u potpunosti analizirati — opcioni deo reda, obavezno C, opcioni deo kolone — inače se tekst vraća netaknut. Zato ROUND(R[-1]C[0], 2) konvertuje samo unutrašnju referencu: iza R u reči ROUND sledi O umesto cifre, zagrade ili C, pa analiza ne uspeva i naziv funkcije prolazi doslovno. Ista logika štiti ROW(), a nazivi funkcija koji počinju slovom C nikada nisu kandidati, jer samo R započinje referencu. Napomene o izdanju v2.175.0 navode da se string literali i identifikatori se takođe preskaču; uprkos tome, ako string literal pod navodnicima u vašoj formuli slučajno sadrži tekst oblikovan tačno kao R1C1 referenca, vredi jednom proveriti kompajlirani izlaz pre nego što se oslonite na njega u produkciji
Baze koordinata i detalji fiksiranja koje vredi znati
Dve konvencije se susreću unutar ovog API-ja, i njihovo pravilno razlikovanje sprečava jedinu stvarnu zamku. Parametri CurRow i CurCol metode GetCompiledFormulaR1C1 su indeksirani od 0, prateći API kalkulatora, dok su brojevi unutar same notacije indeksirani od 1, prateći ono što Excel prikazuje: R2C3 je red 2, kolona 3, što je $C$2, a ne $D$3. Ako je vaš brojač petlje već indeksiran od 0, prosleđujete ga direktno kao CurRow; podešavanje + 1 živi unutar konvertora, a ne u vašem kodu
Još jedan detalj je važan ako će kompajlirana formula nadživeti ćeliju za koju je kompajlirana. Kada izostavite deo za red ili kolonu — oblici RC[-1] ili R[2]C — izostavljena koordinata se razrešava u odnosu na ćeliju domaćina i emituje kao apsolutna koordinata fiksirana znakom $ u konvertovanom A1 tekstu. Tokom evaluacije to je nevidljivo, jer je vrednost ista u oba slučaja. Ali relativno-naspram-apsolutno fiksiranje odlučuje o tome kako se reference pomeraju kada se redovi ili kolone kasnije umetnu ili obrišu, kao što je pokriveno u pratećem članku o prilagođavanju referenci formula. Ako vam je potrebno da koordinata ostane relativna kroz strukturne izmene, napišite pomak eksplicitno — R[0]C[-1] umesto RC[-1] — kako bi konvertor emitovao nefiksiranu A1 referencu
Kompajliranje R1C1 je deo mehanizma formula u HotXLS Delphi Excel komponenti, zajedno sa A1 kompajlerom, grafom ponovnog proračuna i API-jem za evaluaciju prikazanim iznad. Ako vaš kod gradi tabele puštajući formule niz kolone u petlji, prelazak tih petlji sa spajanja stringova za A1 na jedinstvenu R1C1 konstantu je jedna od najjeftinijih nadogradnji pouzdanosti koje su dostupne