HotXLS kompilerar formler skrivna i R1C1-referensnotation via TXLSCalculator.GetCompiledFormulaR1C1, som accepterar former som R2C3 (absolut), R[-1]C[2] (relativ förskjutning) och RC (den aktuella cellen), konverterar dem till A1-notation baserat på rad och kolumn för cellen där formeln lever, och skickar resultatet till samma kompilator som hanterar vanliga A1-formler. För Delphi- och C++Builder-kod som genererar samma formel över hundratals rader, tar den metoden bort en hel klass av strängkonkateringsbuggar
Buggklassen är bekant för alla som har fyllt en kolumn programmatiskt. Man loopar över rader och för varje rad bygger man en A1-formelsträng med Format('D%d*E%d', [Row, Row]). Varje iteration infogar radnummer i texten, och radnumren är den enda del som ändras. Får man förskjutningen fel en gång, blandar ihop en 0-baserad loopräknare med 1-baserade A1-radnummer, eller flyttar datablocket med en rubrikrad, pekar varje formel i kolumnen en rad fel. Ingenting genererar fel; siffrorna blir helt enkelt felaktiga. Formeln du faktiskt menade, "multiplicera de två cellerna till vänster om mig", nämner aldrig något radnummer överhuvudtaget, och R1C1-notation låter dig skriva den på det sättet
Vad är R1C1-notation och när ska du använda den?
R1C1-notation adresserar celler via rad- och kolumnnummer istället för kolumnbokstav plus radnummer, och den markerar relativa referenser som explicita förskjutningar från formelcellen. R2C3 är den absoluta cellen på rad 2, kolumn 3, vilket A1 stavar $C$2. R[-1]C[2] är en rad upp och två kolumner till höger om var formeln än sitter. RC är själva formelcellen. De inom parentes placerade förskjutningarna är själva poängen: en relativ referens i R1C1 ser likadan ut oavsett vilken cell som är värd, medan A1-renderingen av samma referens ändras med varje rad
Notationen visar sitt värde i framför allt ett scenario, och det är ett vanligt sådant: mallgenerering, där samma relativa formel måste placeras på varje rad i ett dataområde. I A1 måste du återskapa formeltexten per rad. I R1C1 är texten en konstant. Detta ligger också närmare hur kalkylbladsfiler tänker internt: poster med delade formler lagrar relativa referenser som rad- och kolumnförskjutningar från värdcellen, så en A1-sträng per rad är något din kod sätter ihop bara för att tolkaren sedan ska plocka isär den igen till förskjutningar. R1C1 hoppar över den rundresan. För interaktiva, människo-skrivna formler förblir A1 det naturliga valet, vilket är anledningen till att det förblir standard överallt i HotXLS
Hur kompilerar HotXLS en R1C1-formel?
HotXLS exponerar funktionen på två nivåer, tillagda i version 2.175.0. TXLSCalculator.GetCompiledFormulaR1C1(UncompiledFormula: String; SheetID, CurRow, CurCol: Integer): TXLSCompiledFormula är den som de flesta kodavsnitt anropar: den returnerar en kompilerad formel klar för utvärdering, precis som dess A1-syskon GetCompiledFormula, men med två extra parametrar som anger den 0-baserade raden och kolumnen för cellen som formeln tillhör. Under den producerar TXLSFormula.GetCompiledR1C1 det råa syntaxträdet, och en fristående funktion R1C1ToA1(const AFormula: String; CurRow, CurCol: Integer): String utför själva notationskonverteringen. Pipelinen är medvetet enkel: översätt R1C1-text till motsvarande A1-text med hjälp av värdcellens koordinater, och kompilera sedan A1-texten via den befintliga motorn — samma motor som löser upp definierade namn och korsbladsreferenser samt hanterar anpassade kalkylbladsfunktioner
Eftersim konverteringen sker före kompileringen beter sig allt nedströms som om du hade skrivit A1-formeln själv. R1C1ToA1('R2C3', 4, 3) returnerar '$C$2' oavsett värdcell, eftersom båda koordinaterna är absoluta. R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3) — en formel som ligger i D5, eftersom CurRow = 4 och CurCol = 3 är 0-baserade — returnerar 'SUM(D2:D4)': förskjutningarna löstes upp mot rad 5, kolumn D, och skickades ut som vanliga relativa A1-referenser. Intervall kräver ingen speciell hantering; kolonet skickas igenom och varje ändpunkt konverteras oberoende av varandra
// 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)
Fylla en kolumn med en relativ formel
Vinsten visar sig i loopen. Jämför A1-versionen, som återskapar formeltexten vid varje iteration, med R1C1-versionen, där formeln är en konstant och endast värdkoordinaterna flyttas. Båda kompileras via TXLSCalculator och utvärderas med GetValue; kalkylatorn tar en callback för celltillhandahållande vid konstruktionen så att utvärderaren kan hämta cellvärden från din datakälla
// 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;
R1C1-loopen har ingen radaritmetik alls i formeltexten. 'RC[-2]*RC[-1]' betyder "samma rad, två kolumner till vänster, gånger samma rad, en kolumn till vänster" på rad 2 och rad 500 likaså, och om datablocket senare flyttas nedåt med en rubrikrad ändras inte formelkonstanten — endast loopgränserna gör det. A1-versionen har två ställen där + 1-justeringen kan bli fel; R1C1-versionen har noll
Vilka R1C1-former accepterar konverteraren?
Konverteraren R1C1ToA1 identifierar de former som dokumenterats för version 2.175.0: R[n]C[m] för relativa förskjutningar i båda riktningarna, RnCm för absolut rad-och-kolumn, R[-n]C[m] med negativa förskjutningar, enbart RC för själva formelcellen samt intervall som R1C1:R3C3 eller R[-1]C:R[1]C. Rad- och kolumnsegmenten tolkas oberoende av varandra, så blandade former som R[1]C3 — relativ rad, absolut kolumn — fungerar också, och bokstäverna är skiftlägesoberoende, så r[-1]c[2] kompilerar på samma sätt som dess versala tvilling. Delar inom parentes blir oankrade (relativa) A1-koordinater; rena siffror blir $-förankrade absoluta koordinater
Den intressanta frågan är hur konverteraren undviker att fördärva allt annat i formeln, eftersom R och C är vanliga bokstäver. Dess urskillningsregel är token-baserad: ett R betraktas endast som början på en referens när det inte föregås av en annan bokstav, och kandidaten måste sedan tolkas helt — valfri raddel, obligatoriskt C, valfri kolumndel — annars återställs texten orörd. Det är därför ROUND(R[-1]C[0], 2) endast konverterar den inre referensen: R i ROUND följs av O snarare än en siffra, parentes eller C, så tolkningen misslyckas och fick namnet släpps igenom oförändrat. Samma logik skyddar ROW(), och funktionsnamn som börjar med C är aldrig kandidater överhuvudtaget, eftersom endast R startar en referens. Versionsnoteringarna för 2.175.0 anger att strängliteraler och identifierare också hoppas över; men om en inom citattecken placerad literal i din formel råkar innehålla text formad exakt som en R1C1-referens, är det ändå värt att kontrollera de kompilerade utdata en gång innan du litar på dem i produktion
Koordinatbaser och förankringsdetaljer värda att känna till
Två konventioner möts i detta API, och att hålla isär dem gör att man undviker den enda egentliga fällan. Parametrarna CurRow och CurCol i GetCompiledFormulaR1C1 är 0-baserade, enligt kalkylator-API:et, medan siffrorna inuti själva notationen är 1-baserade, vilket matchar vad Excel visar: R2C3 är rad 2, kolumn 3, vilket är $C$2, inte $D$3. Om din loopräknare redan är 0-baserad skickar du den direkt som CurRow; + 1-justeringen lever inuti konverteraren, inte i din kod
Ytterligare en detalj är viktig om den kompilerade formeln kommer att överleva cellen den kompilerades för. När du utelämnar en rad- eller kolumndel — formen RC[-1] eller R[2]C — löses den utelämnade koordinaten upp till värdcellen och skickas ut som en absolut, $-förankrad koordinat i den konverterade A1-texten. Vid utvärderingstillfället är detta osynligt, eftersom värdet är detsamma i båda fallen. Men relativ kontra absolut förankring avgör hur referenser förskjuts när rader eller kolumner infogas eller tas bort senare, vilket behandlas i artikeln om justering av formelreferenser. Om du behöver att en koordinat ska förbli relativ genom strukturella redigeringar, skriv förskjutningen explicit — R[0]C[-1] istället för RC[-1] — så att konverteraren skickar ut en oankrad A1-referens
R1C1-kompilering är en del av formelmotorn i HotXLS Delphi Excel Component, tillsammans med A1-kompilatorn, omräkningsgrafen och det utvärderings-API som visas ovan. Om din kod bygger kalkylblad genom att loopa formler nedåt i kolumner, är att flytta dessa loopar från strängkonkaterad A1 till en enda R1C1-konstant en av de enklaste tillförlitlighetsuppgraderingarna som finns