HotXLS kompiliert in R1C1-Bezugsnotation geschriebene Formeln über TXLSCalculator.GetCompiledFormulaR1C1. Dies akzeptiert Formen wie R2C3 (absolut), R[-1]C[2] (relativer Offset) und RC (die aktuelle Zelle), konvertiert sie in die A1-Notation basierend auf der Zeile und Spalte der Zelle, in der sich die Formel befindet, und übergibt das Ergebnis an denselben Compiler, der auch normale A1-Formeln verarbeitet. Für Delphi- und C++Builder-Code, der dieselbe Formel über Hunderte von Zeilen hinweg generiert, eliminiert diese eine Methode eine ganze Klasse von Fehlern bei der Zeichenkettenverkettung
Diese Fehlerklasse ist jedem vertraut, der schon einmal eine Spalte programmatisch gefüllt hat. Sie durchlaufen Zeilen in einer Schleife und erstellen für jede Zeile eine A1-Formelzeichenkette mit Format('D%d*E%d', [Row, Row]). Jede Iteration fügt Zeilennummern in den Text ein, und die Zeilennummern sind der einzige Teil, der sich ändert. Wenn Sie den Offset nur einmal falsch berechnen, einen 0-basierten Schleifenzähler mit 1-basierten A1-Zeilennummern verwechseln oder den Datenblock um eine Kopfzeile verschieben, verweist jede Formel in der Spalte um eine Zeile daneben. Es wird keine Ausnahme ausgelöst; die Zahlen sind einfach falsch. Die Formel, die Sie eigentlich meinten, "multipliziere die beiden Zellen links von mir", erwähnt überhaupt keine Zeilennummer, und die R1C1-Notation ermöglicht es Ihnen, sie genau so zu schreiben
Was ist die R1C1-Notation und wann sollten Sie sie verwenden?
Was ist die R1C1-Notation und wann sollten Sie sie verwenden?
Die R1C1-Notation adressiert Zellen nach Zeilen- und Spaltennummer statt nach Spaltenbuchstabe plus Zeilennummer, und sie markiert relative Bezüge als explizite Offsets von der Formelzelle aus. R2C3 ist die absolute Zelle in Zeile 2, Spalte 3, was in A1 als $C$2 geschrieben wird. R[-1]C[2] ist eine Zeile höher und zwei Spalten rechts von der Zelle, in der sich die Formel befindet. RC is die Formelzelle selbst. Die in eckigen Klammern gesetzten Offsets sind der entscheidende Punkt: Ein relativer Bezug in R1C1 liest sich immer gleich, unabhängig davon, in welcher Zelle er sich befindet, während sich die A1-Darstellung desselben Bezugs mit jeder Zeile ändert
Die Notation bewährt sich in genau einem Szenario, das jedoch sehr häufig vorkommt: bei der Vorlagengenerierung, wenn dieselbe relative Formel in jede Zeile eines Datenbereichs eingefügt werden muss. In A1 müssen Sie den Formeltext pro Zeile neu erstellen. In R1C1 ist der Text eine Konstante. Dies entspricht auch eher der internen Logik von Tabellenkalkulationsdateiformaten: Einträge für gemeinsame Formeln speichern relative Bezüge als Zeilen- und Spalten-Offsets von der Host-Zelle, sodass eine A1-Zeichenkette pro Zeile etwas ist, das Ihr Code nur synthetisiert, damit der Parser sie direkt wieder in Offsets zerlegen kann. R1C1 überspringt diesen Umweg. Für interaktive, von Menschen erstellte Formeln A1 bleibt die natürliche Wahl, weshalb es überall in HotXLS der Standard bleibt
Wie kompiliert HotXLS eine R1C1-Formel?
HotXLS stellt diese Funktion auf zwei Ebenen bereit, die in v2.175.0 hinzugefügt wurden. TXLSCalculator.GetCompiledFormulaR1C1(UncompiledFormula: String; SheetID, CurRow, CurCol: Integer): TXLSCompiledFormula ist die Methode, die von den meisten Programmen aufgerufen wird: Sie gibt eine kompilierte Formel zurück, die zur Auswertung bereit ist, genau wie ihr A1-Gegenstück GetCompiledFormula, jedoch mit zwei zusätzlichen Parametern, die die 0-basierte Zeile und Spalte der Zelle angeben, zu der die Formel gehört. Darunter erzeugt TXLSFormula.GetCompiledR1C1 den rohen Syntaxbaum, und eine eigenständige Funktion R1C1ToA1(const AFormula: String; CurRow, CurCol: Integer): String führt die tatsächliche Notationskonvertierung durch. Die Pipeline ist bewusst einfach gehalten: Konvertieren Sie den R1C1-Text unter Verwendung der Koordinaten der Host-Zelle in den entsprechenden A1-Text und kompilieren Sie den A1-Text dann über die bestehende Engine — dieselbe Engine, die auch definierte Namen und blattübergreifende Bezüge auflöst und benutzerdefinierte Arbeitsblattfunktionen aufruft
Because conversion happens before compilation, everything downstream behaves as if you had written the A1 formula yourself. R1C1ToA1('R2C3', 4, 3) returns '$C$2' regardless of the host cell, because both coordinates are absolute. R1C1ToA1('SUM(R[-3]C[0]:R[-1]C[0])', 4, 3) — eine Formel living in D5, since CurRow = 4 and CurCol = 3 are 0-based — returns 'SUM(D2:D4)': the offsets were resolved against row 5, column D, and emitted as plain relative A1 references. Ranges need no special casing; the colon passes through and each endpoint converts independently
// 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)
Füllen einer Spalte mit einer einzigen relativen Formel
Der Vorteil zeigt sich in der Schleife. Vergleichen Sie die A1-Version, die den Formeltext bei jeder Iteration neu generiert, mit der R1C1-Version, bei der die Formel eine Konstante ist und sich nur die Host-Koordinaten ändern. Beide werden über TXLSCalculator kompiliert und mit GetValue ausgewertet; der Rechner übernimmt bei der Erstellung einen Zellbereitsteller-Callback, sodass der Evaluator Zellwerte aus Ihrer Datenquelle abrufen kann
// 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;
Die R1C1-Schleife enthält keinerlei Zeilenarithmetik im Formeltext. 'RC[-2]*RC[-1]' bedeutet sowohl in Zeile 2 als auch in Zeile 500 "gleiche Zeile, zwei Spalten links, mal gleiche Zeile, eine Spalte links", und wenn sich der Datenblock später um eine Kopfzeile nach unten verschiebt, ändert sich die Formelkonstante nicht — nur die Schleifengrenzen ändern sich. Bei der A1-Version gibt es zwei Stellen, an denen die + 1-Anpassung falsch sein kann; bei der R1C1-Version gibt es null
Welche R1C1-Formen akzeptiert der Konverter?
Der R1C1ToA1-Konverter erkennt die für v2.175.0 dokumentierten Formen: R[n]C[m] für relative Offsets in beide Richtungen, RnCm für absolute Zeilen und Spalten, R[-n]C[m] mit negativen Offsets, das einfache RC für die Formelzelle selbst sowie Bereiche wie R1C1:R3C3 oder R[-1]C:R[1]C. Zeilen- und Spaltenteile werden unabhängig voneinander analysiert, sodass auch gemischte Formen wie R[1]C3 — relative Zeile, absolute Spalte — funktionieren. Die Buchstaben sind nicht fallungsabhängig (case-insensitive), sodass r[-1]c[2] genauso kompiliert wird wie sein Gegenstück in Großbuchstaben. In Klammern gesetzten Teile werden zu ungebundenen (relativen) A1-Koordinaten; reine Zahlen werden zu mit $ verankerten absoluten Koordinaten
Die interessante Frage ist wie der Konverter vermeidet, alles andere in der Formel zu beschädigen, da R und C häufig vorkommende Buchstaben sind. Seine Unterscheidungsregel ist Token-basiert: Ein R wird nur dann als Beginn eines Bezugs betrachtet, wenn ihm kein anderer Buchstabe vorausgeht, und der Kandidat muss sich dann vollständig analysieren lassen — optionaler Zeilenteil, zwingendes C, optionaler Spaltenteil —, andernfalls wird der Text unverändert wiederhergestellt. Aus diesem Grund konvertiert ROUND(R[-1]C[0], 2) nur den inneren Bezug: Auf das R in ROUND folgt ein O statt einer Ziffer, einer Klammer oder eines C, sodass die Analyse fehlschlägt und der Funktionsname unverändert durchgelassen wird. Dieselbe Logik schützt ROW(), und Funktionsnamen, die mit C beginnen, kommen als Kandidaten überhaupt nicht in Frage, da nur R einen Bezug einleitet. In den Versionshinweisen zu v2.175.0 wird angegeben, dass auch Zeichenfolgenliterale und Bezeichner übersprungen werden; dennoch lohnt es sich, die kompilierte Ausgabe einmal zu überprüfen, bevor man ihr in der Produktion vertraut, falls ein in Anführungszeichen gesetztes Literal in Ihrer Formel Text enthält, der exakt wie ein R1C1-Bezug geformt ist
Wissenswerte Details zu Koordinatenbasen und Verankerungen
In dieser API treffen zwei Konventionen aufeinander. Sie auseinanderzuhalten verhindert die einzige echte Falle. Die Parameter CurRow und CurCol von GetCompiledFormulaR1C1 sind 0-basiert, folgend der Calculator-API, während die Nummern innerhalb der Notation selbst sind 1-basiert, entsprechend dem, was Excel anzeigt: R2C3 ist Zeile 2, Spalte 3, was $C$2 und nicht $D$3 entspricht. Wenn Ihr Schleifenzähler bereits 0-basiert ist, übergeben Sie ihn direkt als CurRow; die + 1 befindet sich im Konverter, nicht in Ihrem Code
Ein weiteres Detail ist wichtig, wenn die kompilierte Formel die Zelle, für die sie kompiliert wurde, überdauert. Wenn Sie einen Zeilen- oder Spaltenteil weglassen — die Formen RC[-1] oder R[2]C —, wird die ausgelassene Koordinate auf die Host-Zelle aufgelöst und als absolute, mit $ verankerte Koordinate im konvertierten A1-Text ausgegeben. Zum Zeitpunkt der Auswertung ist dies unsichtbar, da der Wert in beiden Fällen gleich ist. Die relative gegenüber der absoluten Verankerung entscheidet jedoch darüber, wie sich Bezüge verschieben, wenn später Zeilen oder Spalten eingefügt oder gelöscht werden, wie im Begleitartikel zur Anpassung von Formelbezügen beschrieben. Wenn Sie möchten, dass eine Koordinate bei strukturellen Bearbeitungen relativ bleibt, schreiben Sie den Offset explizit — R[0]C[-1] anstelle von RC[-1] —, damit der Konverter einen ungebundenen A1-Bezug ausgibt
Die R1C1-Kompilierung ist Teil der Formel-Engine in der HotXLS Delphi Excel-Komponente, neben dem A1-Compiler, dem Neuberechnungsgraphen und der oben gezeigten Evaluierungs-API. Wenn Ihr Code Tabellenkalkulationen erstellt, indem er Formeln in Schleifen über Spalten hinweg einträgt, ist die Umstellung dieser Schleifen von Zeichenketten-verknüpften A1-Formeln auf eine einzige R1C1-Konstante eines der günstigsten Zuverlässigkeits-Upgrades, die verfügbar sind