diff --git a/components/fpspreadsheet/fpsmath.pas b/components/fpspreadsheet/fpsmath.pas
index aa5393f37..f4b62bef1 100644
--- a/components/fpspreadsheet/fpsmath.pas
+++ b/components/fpspreadsheet/fpsmath.pas
@@ -107,14 +107,22 @@ function fpsNOT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsOR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsTRUE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
{ String functions }
+function fpsCHAR (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsCODE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsLEFT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsLOWER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsMID (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsPROPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsREPLACE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsRIGHT (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+function fpsSUBSTITUTE (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsTRIM (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
function fpsUPPER (Args: TsArgumentStack; NumArgs: Integer): TsArgument;
implementation
uses
- Math;
+ Math, lazutf8, StrUtils, fpsUtils;
type
TBoolArray = array of boolean;
@@ -736,6 +744,7 @@ begin
end;
function fpsLOG(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// LOG( number, [base] )
var
arg_base, arg_number: TsArgument;
data: TFloatArray;
@@ -869,6 +878,7 @@ end;
function fpsAVEDEV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
// Average value of absolute deviations of data from their mean.
+// AVEDEV( argument1, [argument2, ... argument_n] )
var
data: TFloatArray;
m: Double;
@@ -884,6 +894,7 @@ begin
end;
function fpsAVERAGE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// AVERAGE( argument1, [argument2, ... argument_n] )
var
data: TFloatArray;
begin
@@ -892,7 +903,9 @@ begin
end;
function fpsCOUNT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
-{ Count non-missing arguments }
+{ Count non-missing arguments
+ COUNT( argument1, [argument2, ... argument_n] )
+}
var
n, i: Integer;
begin
@@ -903,6 +916,7 @@ begin
end;
function fpsMAX(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// MAX( number1, number2, ... number_n )
var
data: TFloatArray;
begin
@@ -911,6 +925,7 @@ begin
end;
function fpsMIN(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// MIN( number1, number2, ... number_n )
var
data: TFloatArray;
begin
@@ -919,6 +934,7 @@ begin
end;
function fpsPRODUCT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// PRODUCT( number1, number2, ... number_n )
var
data: TFloatArray;
i: Integer;
@@ -933,6 +949,7 @@ begin
end;
function fpsSTDEV(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// STDEV( number1, [number2, ... number_n] )
var
data: TFloatArray;
begin
@@ -941,6 +958,7 @@ begin
end;
function fpsSTDEVP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// STDEVP( number1, [number2, ... number_n] )
var
data: TFloatArray;
begin
@@ -949,6 +967,7 @@ begin
end;
function fpsSUM(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// SUM( value1, [value2, ... value_n] )
var
data: TFloatArray;
begin
@@ -957,6 +976,7 @@ begin
end;
function fpsSUMSQ(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// SUMSQ( value1, [value2, ... value_n] )
var
data: TFloatArray;
begin
@@ -965,6 +985,7 @@ begin
end;
function fpsVAR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// VAR( number1, number2, ... number_n )
var
data: TFloatArray;
begin
@@ -973,6 +994,7 @@ begin
end;
function fpsVARP(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// VARP( number1, number2, ... number_n )
var
data: TFloatArray;
begin
@@ -984,6 +1006,7 @@ end;
{ Logical functions }
function fpsAND(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// AND( condition1, [condition2], ... )
var
data: TBoolArray;
i: Integer;
@@ -1002,11 +1025,13 @@ begin
end;
function fpsFALSE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// FALSE( )
begin
Result := CreateBool(false);
end;
function fpsIF(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// IF( condition, [value_if_true], [value_if_false] )
var
condition: TsArgument;
case1, case2: TsArgument;
@@ -1026,6 +1051,7 @@ begin
end;
function fpsNOT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// NOT( logical_value )
var
data: TBoolArray;
begin
@@ -1034,6 +1060,7 @@ begin
end;
function fpsOR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// OR( condition1, [condition2], ... )
var
data: TBoolArray;
i: Integer;
@@ -1052,6 +1079,7 @@ begin
end;
function fpsTRUE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// TRUE ( )
begin
Result := CreateBool(true);
end;
@@ -1059,28 +1087,191 @@ end;
{ String functions }
+function fpsCHAR(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// CHAR( ascii_value )
+var
+ data: TFloatArray;
+begin
+ if PopFloatValues(Args, 1, data, Result) then begin
+ if (data[0] >= 0) and (data[0] <= 255) then
+ Result := CreateString(AnsiToUTF8(Char(Round(data[0]))));
+ end;
+end;
+
+function fpsCODE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// CODE( text )
+var
+ data: TStrArray;
+begin
+ if PopStringValues(Args, 1, data, Result) then begin
+ if Length(data) > 0 then
+ Result := CreateNumber(Ord(UTF8ToAnsi(data[0])[1]))
+ else
+ Result := CreateEmpty;
+ end;
+end;
+
+function fpsLEFT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// LEFT( text, [number_of_characters] )
+var
+ arg1, arg2: TsArgument;
+ count: Integer;
+ s: String;
+begin
+ count := 1;
+ if NumArgs = 2 then begin
+ arg2 := Args.Pop;
+ if not arg2.IsMissing then begin
+ if arg2.ArgumentType <> atNumber then begin
+ Result := createError(errWrongType);
+ exit;
+ end;
+ count := Round(arg2.NumberValue);
+ end;
+ end;
+ arg1 := Args.Pop;
+ if arg1.ArgumentType <> atString then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ s := arg1.StringValue;
+ Result := CreateString(UTF8LeftStr(s, count));
+end;
+
function fpsLOWER(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// LOWER( text )
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
- Result := CreateString(lowercase(data[0]));
+ Result := CreateString(UTF8LowerCase(data[0]));
+end;
+
+function fpsMID(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// MID( text, start_position, number_of_characters )
+var
+ fdata: TFloatArray;
+ sdata: TStrArray;
+begin
+ if PopFloatValues(Args, 2, fdata, Result) then
+ if PopStringValues(Args, 1, sdata, Result) then
+ Result := CreateString(UTF8Copy(sdata[0], Round(fData[0]), Round(fdata[1])));
+end;
+
+function fpsPROPER(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// PROPER( text )
+var
+ data: TStrArray;
+begin
+ if PopStringValues(Args, 1, data, Result) then
+ Result := CreateString(UTF8ProperCase(data[0]));
+end;
+
+function fpsREPLACE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// REPLACE( old_text, start, number_of_chars, new_text )
+var
+ arg_new, arg_old, arg_start, arg_count: TsArgument;
+ s, s1, s2, snew: String;
+ p, count: Integer;
+begin
+ arg_new := Args.Pop;
+ if arg_new.ArgumentType <> atString then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ arg_count := Args.Pop;
+ if arg_count.ArgumentType <> atNumber then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ arg_start := Args.Pop;
+ if arg_start.ArgumentType <> atNumber then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ arg_old := Args.Pop;
+ if arg_old.ArgumentType <> atString then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+
+ s := arg_old.StringValue;
+ snew := arg_new.StringValue;
+ p := round(arg_start.NumberValue);
+ count := round(arg_count.NumberValue);
+
+ s1 := UTF8Copy(s, 1, p-1);
+ s2 := UTF8Copy(s, p+count, UTF8Length(s));
+ Result := CreateString(s1 + snew + s2);
+end;
+
+function fpsRIGHT(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// RIGHT( text, [number_of_characters] )
+var
+ arg1, arg2: TsArgument;
+ count: Integer;
+ s: String;
+begin
+ count := 1;
+ if NumArgs = 2 then begin
+ arg2 := Args.Pop;
+ if not arg2.IsMissing then begin
+ if arg2.ArgumentType <> atNumber then begin
+ Result := createError(errWrongType);
+ exit;
+ end;
+ count := round(arg2.NumberValue);
+ end;
+ end;
+ arg1 := Args.Pop;
+ if arg1.ArgumentType <> atString then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ s := arg1.StringValue;
+ Result := CreateString(UTF8RightStr(s, count));
+end;
+
+function fpsSUBSTITUTE(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// SUBSTITUTE( text, old_text, new_text, [nth_appearance] )
+var
+ data: TStrArray;
+ arg_n: TsArgument;
+ n: Integer;
+begin
+ n := -1;
+ if NumArgs = 4 then begin
+ arg_n := Args.Pop;
+ if arg_n.ArgumentType <> atNumber then begin
+ Result := CreateError(errWrongType);
+ exit;
+ end;
+ n := round(arg_n.Numbervalue);
+ end;
+ if PopStringValues(Args, 3, data, Result) then begin
+ if n = -1 then
+ Result := CreateString(UTF8StringReplace(data[0], data[1], data[2], [rfReplaceall]))
+ else
+ raise Exception.Create('not implemented');
+ end;
end;
function fpsTRIM(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// TRIM( text )
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
- Result := CreateString(trim(data[0]));
+ Result := CreateString(UTF8Trim(data[0]));
end;
function fpsUPPER(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
+// UPPER( text )
var
data: TStrArray;
begin
if PopStringValues(Args, NumArgs, data, Result) then
- Result := CreateString(uppercase(data[0]));
+ Result := CreateString(UTF8UpperCase(data[0]));
end;
end.
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index e9049283a..bcda50b29 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -1202,15 +1202,15 @@ const
(Symbol:'OR'; MinParams:1; MaxParams:30; Func:fpsOR), // fekOR
(Symbol:'TRUE'; MinParams:0; MaxParams:0; Func:fpsTRUE), // fekTRUE
{ string }
- (Symbol:'CHAR'; MinParams:1; MaxParams:1; Func:nil), // fekCHAR
- (Symbol:'CODE'; MinParams:1; MaxParams:1; Func:nil), // fekCODE
- (Symbol:'LEFT'; MinParams:1; MaxParams:2; Func:nil), // fekLEFT
+ (Symbol:'CHAR'; MinParams:1; MaxParams:1; Func:fpsCHAR), // fekCHAR
+ (Symbol:'CODE'; MinParams:1; MaxParams:1; Func:fpsCODE), // fekCODE
+ (Symbol:'LEFT'; MinParams:1; MaxParams:2; Func:fpsLEFT), // fekLEFT
(Symbol:'LOWER'; MinParams:1; MaxParams:1; Func:fpsLOWER), // fekLOWER
- (Symbol:'MID'; MinParams:3; MaxParams:3; Func:nil), // fekMID
- (Symbol:'PROPER'; MinParams:1; MaxParams:1; Func:nil), // fekPROPER
- (Symbol:'REPLACE'; MinParams:4; MaxParams:4; Func:nil), // fekREPLACE
- (Symbol:'RIGHT'; MinParams:1; MaxParams:2; Func:nil), // fekRIGHT
- (Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4; Func:nil), // fekSUBSTITUTE
+ (Symbol:'MID'; MinParams:3; MaxParams:3; Func:fpsMID), // fekMID
+ (Symbol:'PROPER'; MinParams:1; MaxParams:1; Func:fpsPROPER), // fekPROPER
+ (Symbol:'REPLACE'; MinParams:4; MaxParams:4; Func:fpsREPLACE), // fekREPLACE
+ (Symbol:'RIGHT'; MinParams:1; MaxParams:2; Func:fpsRIGHT), // fekRIGHT
+ (Symbol:'SUBSTITUTE';MinParams:3; MaxParams:4; Func:fpsSUBSTITUTE), // fekSUBSTITUTE
(Symbol:'TRIM'; MinParams:1; MaxParams:1; Func:fpsTRIM), // fekTRIM
(Symbol:'UPPER'; MinParams:1; MaxParams:1; Func:fpsUPPER), // fekUPPER
{ lookup/reference }
diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas
index 8608eae17..7e4743692 100644
--- a/components/fpspreadsheet/fpsutils.pas
+++ b/components/fpspreadsheet/fpsutils.pas
@@ -77,6 +77,7 @@ function GetCellRangeString(ARow1, ACol1, ARow2, ACol2: Cardinal; AFlags: TsRelF
function GetErrorValueStr(AErrorValue: TsErrorValue): String;
+function UTF8ProperCase(AText: String): String;
function UTF8TextToXMLText(AText: ansistring): ansistring;
function IfThen(ACondition: Boolean; AValue1,AValue2: TsNumberFormat): TsNumberFormat; overload;
@@ -139,7 +140,7 @@ var
implementation
uses
- Math;
+ Math, lazutf8;
{******************************************************************************}
{ Endianess helper functions }
@@ -662,6 +663,42 @@ begin
end;
end;
+{@@
+ Converts a string to "proper case", i.e. 1st character of each word is
+ upper-case, other characters are lowercase.
+ @param S String to be converted
+ @return String in proper case }
+function UTF8ProperCase(AText: String): String;
+begin
+ result := '';
+end;
+ (*
+const
+ Delims: TSysCharSet = ['0'..'9', ' ', '.', ',', ';', ':', '-', '_',
+ '<', '>', '|', '''', '#', '*', '+', '~', '!', '"', '§', '$', '%', '&', '/', '(', ')', '=',
+ '?', '\', '}', ']', '[', '{', '@'];
+var
+ ch: String;
+ len, i, j: Integer;
+ res: string;
+ w: String;
+ p: Integer;
+ words: Array of String;
+begin
+ AText := UTF8Lowercase(AText);
+
+ i := 0;
+ w := 'dummy';
+ Result := '';
+ while w <> '' do begin
+ w := ExtractWordPos(i, AText, Delims, p);
+ Result := UTF8Copy(AText, 1, p-1) + UTF8Uppercase(UTF8Copy(w, 1, 1)) +
+ UTF8Copy(w, 2, Length(w)-1);
+ inc(i);
+ end;
+end;
+ *)
+
{@@
Converts a string encoded in UTF8 to a string usable in XML. For this purpose,
some characters must be translated.
diff --git a/components/fpspreadsheet/tests/formulatests.pas b/components/fpspreadsheet/tests/formulatests.pas
index c2a6893a5..ac49f3169 100644
--- a/components/fpspreadsheet/tests/formulatests.pas
+++ b/components/fpspreadsheet/tests/formulatests.pas
@@ -49,7 +49,7 @@ type
implementation
uses
- math, typinfo, fpsUtils, rpnFormulaUnit;
+ math, typinfo, lazUTF8, fpsUtils, rpnFormulaUnit;
{ TSpreadWriteReadFormatTests }
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index f9bb72a93..86230b550 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -47,9 +47,6 @@
-
-
-
@@ -129,7 +126,6 @@
-
@@ -139,7 +135,6 @@
-
@@ -159,9 +154,6 @@
-
-
-
diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
index d3222d12f..4c33ba4c6 100644
--- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
+++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
@@ -1045,6 +1045,63 @@
{ String functions }
{------------------------------------------------------------------------------}
+ // CHAR
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=CHAR(72)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNNumber(72,
+ RPNFunc(fekCHAR, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString(char(72));
+
+ // CODE
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=CODE("Hallo word")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNFunc(fekCODE, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateNumber(ord('H'));
+
+ // LEFT (2 parameters)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=LEFT("Hallo word", 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNNumber(2,
+ RPNFunc(fekLEFT, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('Ha');
+
+ // LEFT (2 parameters, utf8)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=LEFT("Ändern", 3)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Ändern',
+ RPNNumber(3,
+ RPNFunc(fekLEFT, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('Änd');
+
+ // LEFT (2 parameters, 1 of them missing)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=LEFT("Hallo word", )');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNMissingArg(
+ RPNFunc(fekLEFT, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('H');
+
+ // LEFT (1 parameter)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=LEFT("Hallo word")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNFunc(fekLEFT, 1, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('H');
+
// Lower case
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=LOWER("Hallo word")');
@@ -1054,6 +1111,115 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString(LowerCase('Hallo world'));
+ // Lower case / utf8
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=LOWER("Viele Grüße")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Viele Grüße',
+ RPNFunc(fekLOWER, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString(UTF8LowerCase('Viele Grüße'));
+
+ // MID
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=MID("Hallo word", 3, 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNNumber(3,
+ RPNNumber(2,
+ RPNFunc(fekMID, nil))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('ll');
+
+ // REPLACE
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=REPLACE("weather", 2, 2, "he")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('weather',
+ RPNNumber(2,
+ RPNNumber(2,
+ RPNString('he',
+ RPNFunc(fekREPLACE, nil)))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('whether');
+
+ // REPLACE / utf8
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=REPLACE("würde", 2, 1, "u")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('würde',
+ RPNNumber(2,
+ RPNNumber(1,
+ RPNString('u',
+ RPNFunc(fekREPLACE, nil)))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('wurde');
+
+// RIGHT (2 parameters)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=RIGHT("Hallo word", 2)');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNNumber(2,
+ RPNFunc(fekRIGHT, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('ld');
+
+ // RIGHT (2 parameters, one of them missing)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=RIGHT("Hallo word", )');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNMissingArg(
+ RPNFunc(fekRIGHT, 2, nil)))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('d');
+
+ // RIGHT (1 parameter)
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=RIGHT("Hallo word")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Hallo world',
+ RPNFunc(fekRIGHT, 1, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('d');
+
+ // SUBSTITUTE
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=SUBSTITUTE("lazarus", "s", "s.exe")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('lazarus',
+ RPNString('s',
+ RPNString('s.exe',
+ RPNFunc(fekSUBSTITUTE, 3, nil))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('lazarus.exe');
+
+ // SUBSTITUTE
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=SUBSTITUTE("lAzArus", "A", "a")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('lAzArus',
+ RPNString('A',
+ RPNString('a',
+ RPNFunc(fekSUBSTITUTE, 3, nil))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('lazarus');
+
+ // SUBSTITUTE / utf8
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=SUBSTITUTE("lÄzÄrus", "Ä", "a")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('lÄzÄrus',
+ RPNString('Ä',
+ RPNString('a',
+ RPNFunc(fekSUBSTITUTE, 3, nil))))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString('lazarus');
+
+ // SUBSTITUTE / 4 parameters
+ // to do...
+
// Trim
inc(Row);
MyWorksheet.WriteUTF8Text(Row, 0, '=TRIM(" Hallo word ")');
@@ -1061,7 +1227,7 @@
RPNString(' Hallo world ',
RPNFunc(fekTRIM, nil))));
SetLength(sollValues, Row+1);
- sollValues[Row] := CreateString(Trim(' Hallo world '));
+ sollValues[Row] := CreateString(UTF8Trim(' Hallo world '));
// Upper case
inc(Row);
@@ -1072,3 +1238,12 @@
SetLength(sollValues, Row+1);
sollValues[Row] := CreateString(UpperCase('Hallo world'));
+ // Upper case / utf8
+ inc(Row);
+ MyWorksheet.WriteUTF8Text(Row, 0, '=UPPER("Viele Grüße")');
+ MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
+ RPNString('Viele Grüße',
+ RPNFunc(fekUPPER, nil))));
+ SetLength(sollValues, Row+1);
+ sollValues[Row] := CreateString(UTF8UpperCase('Viele Grüße'));
+