fpspreadsheet: Complete rpn calculations (COUNTA). Remaining missing function probably will not be implemented because calculation is beyond units (math, strutils, dateutils; if needed they can still be implemented at application level by registering the corresponding function).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3296 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-07-07 21:29:00 +00:00
parent 328cce376e
commit 7e22f0e6ad
4 changed files with 74 additions and 6 deletions

View File

@ -11,6 +11,8 @@ type
TsArgumentType = (atCell, atCellRange, atNumber, atString,
atBool, atError, atEmpty);
TsArgumentTypes = set of TsArgumentType;
TsArgBoolArray = array of boolean;
TsArgNumberArray = array of double;
TsArgStringArray = array of string;
@ -128,6 +130,7 @@ function fpsYEAR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsAVEDEV (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsAVERAGE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNTA (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNTBLANK (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsCOUNTIF (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsMAX (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
@ -1534,7 +1537,7 @@ end;
function fpsCOUNT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ counts the number of cells that contain numbers as well as the number of
arguments that contain numbers.
COUNT( argument1, [argument2, ... argument_n] )
COUNT( argument1 [, argument2, ... argument_n] )
}
var
data: TsArgNumberArray;
@ -1543,6 +1546,38 @@ begin
Result := CreateNumberArg(Length(data));
end;
function fpsCOUNTA(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
// COUNTA (argument1 [, argument2, ... argument_n] )
// Counts the number of non-empty cells specified by arguments of misc type.
var
arg: TsArgument;
counter: Integer;
r, c: Integer;
cell: PCell;
n: Integer;
begin
n := 0;
// The order of arguments is not important for counting --> we just pop them from the stack.
for counter := 1 to NumArgs do begin
arg := Args.Pop;
case arg.ArgumentType of
atCell:
if arg.Cell^.ContentType <> cctEmpty then inc(n);
atCellRange:
for r := arg.FirstRow to arg.LastRow do
for c := arg.FirstCol to arg.LastCol do begin
cell := arg.Worksheet.FindCell(r, c);
if (cell <> nil) and (cell^.ContentType <> cctEmpty) then inc(n);
end;
atString:
if arg.StringValue <> '' then inc(n);
atNumber, atBool, atError:
inc(n);
end;
end;
Result := CreateNumberArg(n);
end;
function fpsCOUNTBLANK(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
// COUNTBLANK( range )
// counts the number of empty cells in a range.

View File

@ -1152,7 +1152,7 @@ var
(Symbol:'<'; MinParams:2; MaxParams:2; Func:fpsLess), // fekLess
(Symbol:'<='; MinParams:2; MaxParams:2; Func:fpsLessEqual), // fekLessEqual
(Symbol:'<>'; MinParams:2; MaxParams:2; Func:fpsNotEqual), // fekNotEqual
(Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen
(Symbol:''; MinParams:1; MaxParams:1; Func:nil), // fekParen -- no need to calculate!
{ math }
(Symbol:'ABS'; MinParams:1; MaxParams:1; Func:fpsABS), // fekABS
(Symbol:'ACOS'; MinParams:1; MaxParams:1; Func:fpsACOS), // fekACOS
@ -1203,7 +1203,7 @@ var
(Symbol:'CHIDIST'; MinParams:2; MaxParams:2; Func:nil), // fekCHIDIST
(Symbol:'CHIINV'; MinParams:2; MaxParams:2; Func:nil), // fekCHIINV
(Symbol:'COUNT'; MinParams:0; MaxParams:30; Func:fpsCOUNT), // fekCOUNT
(Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:nil), // fekCOUNTA
(Symbol:'COUNTA'; MinParams:0; MaxParams:30; Func:fpsCOUNTA), // fekCOUNTA
(Symbol:'COUNTBLANK';MinParams:1; MaxParams:1; Func:fpsCOUNTBLANK), // fekCOUNTBLANK
(Symbol:'COUNTIF'; MinParams:2; MaxParams:2; Func:fpsCOUNTIF), // fekCOUNTIF
(Symbol:'MAX'; MinParams:1; MaxParams:30; Func:fpsMAX), // fekMAX

View File

@ -80,7 +80,6 @@
<Unit1>
<Filename Value="datetests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="datetests"/>
</Unit1>
<Unit2>
<Filename Value="stringtests.pas"/>
@ -89,12 +88,10 @@
<Unit3>
<Filename Value="numberstests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="numberstests"/>
</Unit3>
<Unit4>
<Filename Value="manualtests.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="manualtests"/>
</Unit4>
<Unit5>
<Filename Value="testsutility.pas"/>

View File

@ -1286,6 +1286,42 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumberArg(2);
// COUNTA
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(1, 1.1, 1.2, 0.9, 0.8)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNFunc(fekCOUNTA, 5, nil))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumberArg(5);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(1, 1.1, 1.2, 0.9, 0.8, "A", "B")');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNNumber(1.0,
RPNNumber(1.1,
RPNNumber(1.2,
RPNNumber(0.9,
RPNNumber(0.8,
RPNString('A',
RPNString('B',
RPNFunc(fekCOUNTA, 7, nil))))))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumberArg(7);
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=COUNTA(A1:C2,1,2,"A")');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNCellRange('A1:C2',
RPNNumber(1,
RPNNumber(2,
RPNString('A',
RPNFunc(fekCOUNTA, 4, nil)))))));
SetLength(sollValues, Row+1);
sollValues[Row] := CreateNumberArg(7);
if AFormat <> sfExcel2 then begin
// COUNTBLANK
inc(Row);