You've already forked lazarus-ccr
fpspreadsheet: Add parsing of cell range strings given in "R1C1" syntax
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4376 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -53,6 +53,7 @@ function DWordLEtoN(AValue: Cardinal): Cardinal;
|
||||
function WideStringLEToN(const AValue: WideString): WideString;
|
||||
|
||||
// Cell, column and row strings
|
||||
// -- "A1" syntax
|
||||
function ParseIntervalString(const AStr: string;
|
||||
out AFirstCellRow, AFirstCellCol, ACount: Cardinal;
|
||||
out ADirection: TsSelectionDirection): Boolean;
|
||||
@ -76,20 +77,28 @@ function ParseCellRowString(const AStr: string;
|
||||
function ParseCellColString(const AStr: string;
|
||||
out AResult: Cardinal): Boolean;
|
||||
|
||||
function ParseCellString_R1C1(const AStr: String; ABaseRow, ABaseCol: Cardinal;
|
||||
out ACellRow, ACellCol: Cardinal; out AFlags: TsRelFlags): Boolean;
|
||||
|
||||
function GetColString(AColIndex: Integer): String;
|
||||
|
||||
function GetCellString(ARow,ACol: Cardinal;
|
||||
AFlags: TsRelFlags = [rfRelRow, rfRelCol]): String;
|
||||
function GetCellString_R1C1(ARow, ACol: Cardinal; AFlags: TsRelFlags = [rfRelRow, rfRelCol];
|
||||
ARefRow: Cardinal = Cardinal(-1); ARefCol: Cardinal = Cardinal(-1)): String;
|
||||
|
||||
function GetCellRangeString(ARow1, ACol1, ARow2, ACol2: Cardinal;
|
||||
AFlags: TsRelFlags = rfAllRel; Compact: Boolean = false): String; overload;
|
||||
function GetCellRangeString(ARange: TsCellRange;
|
||||
AFlags: TsRelFlags = rfAllRel; Compact: Boolean = false): String; overload;
|
||||
function GetCellString(ARow,ACol: Cardinal;
|
||||
AFlags: TsRelFlags = [rfRelRow, rfRelCol]): String;
|
||||
function GetColString(AColIndex: Integer): String;
|
||||
|
||||
// -- "R1C1" syntax
|
||||
function ParseCellRangeString_R1C1(const AStr: string; ABaseRow, ABaseCol: Cardinal;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||
out AFlags: TsRelFlags): Boolean;
|
||||
function ParseCellString_R1C1(const AStr: String; ABaseRow, ABaseCol: Cardinal;
|
||||
out ACellRow, ACellCol: Cardinal; out AFlags: TsRelFlags): Boolean; overload;
|
||||
function ParseCellString_R1C1(const AStr: string; ABaseRow, ABaseCol: Cardinal;
|
||||
out ACellRow, ACellCol: Cardinal): Boolean; overload;
|
||||
|
||||
function GetCellString_R1C1(ARow, ACol: Cardinal; AFlags: TsRelFlags = [rfRelRow, rfRelCol];
|
||||
ARefRow: Cardinal = Cardinal(-1); ARefCol: Cardinal = Cardinal(-1)): String;
|
||||
|
||||
|
||||
// Error strings
|
||||
|
||||
function GetErrorValueStr(AErrorValue: TsErrorValue): String;
|
||||
function TryStrToErrorValue(AErrorStr: String; out AErr: TsErrorValue): boolean;
|
||||
@ -587,6 +596,54 @@ begin
|
||||
Result := Scan(1);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Extracts information on cell range from a cellrange string in "R1C1" notation.
|
||||
Returns in AFlags also information on relative/absolute cells.
|
||||
|
||||
@param AStr Cell range string, in R1C1 syntax,
|
||||
such as R[2]C[3]:R[4]C[8]
|
||||
@param ABaseRow Row index from which the cell reference is seen.
|
||||
@param ABaseCol Column index from which the cell reference is seen.
|
||||
@param AFirstCellRow Row index of the top/left cell of the range (output)
|
||||
@param AFirstCellCol Column index of the top/left cell of the range (output)
|
||||
@param ALastCellRow Row index of the bottom/right cell of the range (output)
|
||||
@param ALastCellCol Column index of the bottom/right cell of the rng (output)
|
||||
@param AFlags A set containing an element for AFirstCellRow,
|
||||
AFirstCellCol, ALastCellRow, ALastCellCol if they
|
||||
represent a relative cell address.
|
||||
|
||||
@return FALSE if the string is not a valid cell range
|
||||
-------------------------------------------------------------------------------}
|
||||
function ParseCellRangeString_R1C1(const AStr: string; ABaseRow, ABaseCol: Cardinal;
|
||||
out AFirstCellRow, AFirstCellCol, ALastCellRow, ALastCellCol: Cardinal;
|
||||
out AFlags: TsRelFlags): Boolean;
|
||||
var
|
||||
p: Integer;
|
||||
s: String;
|
||||
f: TsRelFlags;
|
||||
begin
|
||||
Result := True;
|
||||
|
||||
// First find the colon
|
||||
p := pos(':', AStr);
|
||||
if p = 0 then exit(false);
|
||||
|
||||
// Analyze part after the colon
|
||||
s := copy(AStr, p+1, Length(AStr));
|
||||
Result := ParseCellString_R1C1(s, ABaseRow, ABaseCol,
|
||||
ALastCellRow, ALastCellCol, f);
|
||||
if not Result then exit;
|
||||
|
||||
// Analyze part before the colon
|
||||
s := copy(AStr, 1, p-1);
|
||||
Result := ParseCellString_R1C1(s, ABaseRow, ABaseCol,
|
||||
AFirstCellRow, AFirstCellCol, AFlags);
|
||||
|
||||
// Add flags of 2nd part
|
||||
if rfRelRow in f then Include(AFlags, rfRelRow2);
|
||||
if rfRelCol in f then Include(AFlags, rfRelCol2);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Parses a cell string in "R1C1" notation into zero-based column and row numbers
|
||||
'AFlags' indicates relative addresses.
|
||||
@ -682,6 +739,28 @@ begin
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Parses a cell string in "R1C1" notation into zero-based column and row numbers
|
||||
|
||||
For compatibility with old version which does not return flags for relative
|
||||
cell addresses.
|
||||
|
||||
@param AStr Cell reference in R1C1 syntax, such as R[2]C[3] or R1C5
|
||||
@param ABaseRow Row index from which the cell reference is seen.
|
||||
@param ABaseCol Column index from which the cell reference is seen.
|
||||
@param ACellRow Row index of the top/left cell of the range (output)
|
||||
@param ACellCol Column index of the top/left cell of the range (output)
|
||||
-------------------------------------------------------------------------------}
|
||||
function ParseCellString_R1C1(const AStr: string; ABaseRow, ABaseCol: Cardinal;
|
||||
out ACellRow, ACellCol: Cardinal): Boolean;
|
||||
var
|
||||
flags: TsRelFlags;
|
||||
begin
|
||||
Result := ParseCellString_R1C1(AStr, ABaseRow, ABaseCol,
|
||||
ACellRow, ACellCol, flags);
|
||||
end;
|
||||
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Parses a cell string, like 'A1' into zero-based column and row numbers
|
||||
Note that there can be several letters to address for more than 26 columns.
|
||||
|
@ -41,6 +41,7 @@ type
|
||||
procedure TestCellString;
|
||||
// Tests cell references given in the "R1C1" syntax.
|
||||
procedure TestCellString_R1C1;
|
||||
procedure TestCellRangeString_R1C1;
|
||||
|
||||
//todo: add more calls, rename sheets, try to get sheets with invalid indexes etc
|
||||
//(see strings tests for how to deal with expected exceptions)
|
||||
@ -599,7 +600,51 @@ begin
|
||||
// (E15) RC interchanged
|
||||
res := ParseCellString_R1C1('C1R1', 10, 10, r, c, flags);
|
||||
CheckEquals(res, false, 'Result mismatch in test E15');
|
||||
end;
|
||||
|
||||
{ Tests cell range references given in the "R1C1" syntax. }
|
||||
procedure TSpreadInternalTests.TestCellRangeString_R1C1;
|
||||
var
|
||||
r1,c1,r2,c2: Cardinal;
|
||||
s: String;
|
||||
flags: TsRelFlags;
|
||||
res: Boolean;
|
||||
begin
|
||||
// (1) Absolute reference of the range between cells row0/cell0 and row2/col1
|
||||
res := ParseCellRangeString_R1C1('R1C1:R3C2', 10, 10, r1, c1, r2, c2, flags);
|
||||
CheckEquals(res, true, 'Result mismatch in test 1');
|
||||
CheckEquals(r1, 0, 'Row1 mismatch in test 1'); // base cell coordinates are ignored with absolute refs!
|
||||
CheckEquals(c1, 0, 'Col1 mismatch in test 1');
|
||||
CheckEquals(r2, 2, 'Row2 mismatch in test 1'); // base cell coordinates are ignored with absolute refs!
|
||||
CheckEquals(c2, 1, 'Col2 mismatch in test 1');
|
||||
CheckEquals(true, flags = [], 'Flags mismatch in test 1');
|
||||
|
||||
// (2) Relative reference of the cell left of col 10 and above row 10
|
||||
res := ParseCellRangeString_R1C1('R[-1]C[-1]:R[1]C[1]', 10, 10, r1, c1, r2, c2, flags);
|
||||
CheckEquals(res, true, 'Result mismatch in test 2');
|
||||
CheckEquals(r1, 9, 'Row mismatch in test 2');
|
||||
CheckEquals(c1, 9, 'Col mismatch in test 2');
|
||||
CheckEquals(r2, 11, 'Row mismatch in test 2');
|
||||
CheckEquals(c2, 11, 'Col mismatch in test 2');
|
||||
CheckEquals(true, flags = [rfRelRow, rfRelCol, rfRelRow2, rfRelCol2], 'Flags mismatch in test 2');
|
||||
|
||||
// (3) Absolute reference of first cell (row0/col0), Relative reference of second cell
|
||||
res := ParseCellRangeString_R1C1('R1C1:R[1]C[1]', 10, 10, r1, c1, r2, c2, flags);
|
||||
CheckEquals(res, true, 'Result mismatch in test 2');
|
||||
CheckEquals(r1, 0, 'Row mismatch in test 3');
|
||||
CheckEquals(c1, 0, 'Col mismatch in test 3');
|
||||
CheckEquals(r2, 11, 'Row mismatch in test 3');
|
||||
CheckEquals(c2, 11, 'Col mismatch in test 3');
|
||||
CheckEquals(true, flags = [rfRelRow2, rfRelCol2], 'Flags mismatch in test 3');
|
||||
|
||||
// (4) Relative reference of first cell, absolute reference of second cell
|
||||
res := ParseCellRangeString_R1C1('R[-1]C[-1]:R20C20', 10, 10, r1, c1, r2, c2, flags);
|
||||
CheckEquals(res, true, 'Result mismatch in test 4');
|
||||
CheckEquals(r1, 9, 'Row mismatch in test 4');
|
||||
CheckEquals(c1, 9, 'Col mismatch in test 4');
|
||||
CheckEquals(r2, 19, 'Row mismatch in test 4');
|
||||
CheckEquals(c2, 19, 'Col mismatch in test 4');
|
||||
CheckEquals(true, flags = [rfRelRow, rfRelCol], 'Flags mismatch in test 4');
|
||||
end;
|
||||
|
||||
procedure TSpreadInternalTests.FractionTest(AMaxDigits: Integer);
|
||||
|
Reference in New Issue
Block a user