fpspreadsheet: Some simplification of number format token analysis. Add number format unit tests for the new formats (fraction, split-off thousands)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4131 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-05-15 21:14:19 +00:00
parent 2d35913169
commit e307a01d51
2 changed files with 112 additions and 31 deletions

View File

@ -89,13 +89,14 @@ type
// Format string // Format string
function BuildFormatString: String; virtual; function BuildFormatString: String; virtual;
// Token analysis // Token analysis
{
function GetTokenIntValueAt(AToken: TsNumFormatToken; function GetTokenIntValueAt(AToken: TsNumFormatToken;
ASection,AIndex: Integer): Integer; ASection,AIndex: Integer): Integer;
function IsNumberAt(ASection,AIndex: Integer; out ANumFormat: TsNumberFormat; function IsNumberAt(ASection,AIndex: Integer; out ANumFormat: TsNumberFormat;
out ADecimals: Byte; out ANextIndex: Integer): Boolean; out ADecimals: Byte; out ANextIndex: Integer): Boolean;
function IsTextAt(AText: string; ASection, AIndex: Integer): Boolean; function IsTextAt(AText: string; ASection, AIndex: Integer): Boolean;
function IsTokenAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Boolean; function IsTokenAt(AToken: TsNumFormatToken; ASection,AIndex: Integer): Boolean;
}
public public
constructor Create(AWorkbook: TsWorkbook; const AFormatString: String); constructor Create(AWorkbook: TsWorkbook; const AFormatString: String);
destructor Destroy; override; destructor Destroy; override;
@ -292,13 +293,11 @@ end;
procedure TsNumFormatParser.CheckSection(ASection: Integer); procedure TsNumFormatParser.CheckSection(ASection: Integer);
var var
el, next, i: Integer; el, i: Integer;
section: PsNumFormatSection; section: PsNumFormatSection;
nfs, nfsTest: String; nfs, nfsTest: String;
nf: TsNumberFormat; nf: TsNumberFormat;
datetimeFormats: set of TsNumberformat; formats: set of TsNumberFormat;
f1,f2: Integer;
decs: Byte;
begin begin
if FStatus <> psOK then if FStatus <> psOK then
exit; exit;
@ -308,6 +307,12 @@ begin
for el := 0 to High(section^.Elements) do for el := 0 to High(section^.Elements) do
case section^.Elements[el].Token of case section^.Elements[el].Token of
nftZeroDecs:
section^.Decimals := section^.Elements[el].IntValue;
nftFracNumSpaceDigit, nftFracNumZeroDigit:
section^.FracNumerator := section^.Elements[el].IntValue;
nftFracDenomSpaceDigit, nftFracDenomZeroDigit:
section^.FracDenominator := section^.Elements[el].IntValue;
nftPercent: nftPercent:
section^.Kind := section^.Kind + [nfkPercent]; section^.Kind := section^.Kind + [nfkPercent];
nftExpChar: nftExpChar:
@ -370,13 +375,18 @@ begin
section^.NumFormat := nfTimeInterval section^.NumFormat := nfTimeInterval
else else
begin begin
datetimeFormats := [nfShortDateTime, nfLongDate, nfShortDate, nfLongTime, formats := [nfShortDateTime, nfLongDate, nfShortDate, nfLongTime,
nfShortTime, nfLongTimeAM, nfShortTimeAM, nfDayMonth, nfMonthYear]; nfShortTime, nfLongTimeAM, nfShortTimeAM, nfDayMonth, nfMonthYear];
for nf in datetimeFormats do for nf in formats do
begin begin
nfsTest := BuildDateTimeFormatString(nf, FWorkbook.FormatSettings); nfsTest := BuildDateTimeFormatString(nf, FWorkbook.FormatSettings);
if Length(nfsTest) = Length(nfs) then if Length(nfsTest) = Length(nfs) then
begin begin
if SameText(nfs, nfsTest) then
begin
section^.NumFormat := nf;
break;
end;
for i := 1 to Length(nfsTest) do for i := 1 to Length(nfsTest) do
case nfsTest[i] of case nfsTest[i] of
'/': if not (nf in [nfLongTimeAM, nfShortTimeAM]) then '/': if not (nf in [nfLongTimeAM, nfShortTimeAM]) then
@ -390,17 +400,28 @@ begin
break; break;
end; end;
end; end;
{
if SameText(nfs, BuildDateTimeFormatString(nf, FWorkbook.FormatSettings)) then
begin
section^.NumFormat := nf;
break;
end;
}
end; end;
end; end;
end else end else
begin begin
nfs := GetFormatString;
formats := [nfFixed, nfFixedTh, nfPercentage, nfExp, nfFraction];
for nf in formats do begin
nfsTest := BuildNumberFormatString(nf, FWorkbook.FormatSettings, section^.Decimals);
if SameText(nfs, nfsTest) then
begin
section^.NumFormat := nf;
break;
end;
end;
if (section^.NumFormat = nfCustom) and (nfkCurrency in section^.Kind) then
begin
section^.NumFormat := nfCurrency;
if section^.Color = scRed then
section^.NumFormat := nfCurrencyRed;
end;
{
el := 0; el := 0;
while el < Length(section^.Elements) do while el < Length(section^.Elements) do
begin begin
@ -470,6 +491,7 @@ begin
end; end;
if (section^.NumFormat = nfCurrency) and (section^.Color = scRed) then if (section^.NumFormat = nfCurrency) and (section^.Color = scRed) then
section^.NumFormat := nfCurrencyRed; section^.NumFormat := nfCurrencyRed;
}
end; end;
end; end;
@ -743,7 +765,7 @@ function TsNumFormatParser.GetParsedSections(AIndex: Integer): TsNumFormatSectio
begin begin
Result := FSections[AIndex]; Result := FSections[AIndex];
end; end;
{
function TsNumFormatParser.GetTokenIntValueAt(AToken: TsNumFormatToken; function TsNumFormatParser.GetTokenIntValueAt(AToken: TsNumFormatToken;
ASection, AIndex: Integer): Integer; ASection, AIndex: Integer): Integer;
begin begin
@ -752,7 +774,7 @@ begin
else else
Result := -1; Result := -1;
end; end;
}
{ Returns true if the format elements contain at least one date/time token } { Returns true if the format elements contain at least one date/time token }
function TsNumFormatParser.IsDateTimeFormat: Boolean; function TsNumFormatParser.IsDateTimeFormat: Boolean;
var var
@ -766,7 +788,7 @@ begin
end; end;
Result := false; Result := false;
end; end;
{
function TsNumFormatParser.IsNumberAt(ASection, AIndex: Integer; function TsNumFormatParser.IsNumberAt(ASection, AIndex: Integer;
out ANumFormat: TsNumberFormat; out ADecimals: Byte; out ANumFormat: TsNumberFormat; out ADecimals: Byte;
out ANextIndex: Integer): Boolean; out ANextIndex: Integer): Boolean;
@ -837,7 +859,7 @@ begin
Result := IsTokenAt(nftText, ASection, AIndex) and Result := IsTokenAt(nftText, ASection, AIndex) and
(FSections[ASection].Elements[AIndex].TextValue = AText); (FSections[ASection].Elements[AIndex].TextValue = AText);
end; end;
}
{ Returns true if the format elements contain only time, no date tokens. } { Returns true if the format elements contain only time, no date tokens. }
function TsNumFormatParser.IsTimeFormat: Boolean; function TsNumFormatParser.IsTimeFormat: Boolean;
var var
@ -851,7 +873,7 @@ begin
end; end;
Result := false; Result := false;
end; end;
{
function TsNumFormatParser.IsTokenAt(AToken: TsNumFormatToken; function TsNumFormatParser.IsTokenAt(AToken: TsNumFormatToken;
ASection, AIndex: Integer): Boolean; ASection, AIndex: Integer): Boolean;
begin begin
@ -859,7 +881,7 @@ begin
(AIndex < Length(FSections[ASection].Elements)) and (AIndex < Length(FSections[ASection].Elements)) and
(FSections[ASection].Elements[AIndex].Token = AToken); (FSections[ASection].Elements[AIndex].Token = AToken);
end; end;
}
{ Limits the decimals to 0 or 2, as required by Excel2. } { Limits the decimals to 0 or 2, as required by Excel2. }
procedure TsNumFormatParser.LimitDecimals; procedure TsNumFormatParser.LimitDecimals;
var var

View File

@ -19,11 +19,14 @@ type
SollNumFormat: TsNumberFormat; SollNumFormat: TsNumberFormat;
SollSectionCount: Integer; SollSectionCount: Integer;
SollDecimals: Byte; SollDecimals: Byte;
SollFactor: Double;
SollNumeratorDigits: Integer;
SollDenominatorDigits: Integer;
SollCurrencySymbol: String; SollCurrencySymbol: String;
end; end;
var var
ParserTestData: Array[0..8] of TParserTestData; ParserTestData: Array[0..10] of TParserTestData;
procedure InitParserTestData; procedure InitParserTestData;
@ -56,6 +59,9 @@ begin
SollNumFormat := nfFixed; SollNumFormat := nfFixed;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 0; SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[1] do begin with ParserTestData[1] do begin
@ -64,6 +70,9 @@ begin
SollNumFormat := nfFixed; SollNumFormat := nfFixed;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 3; SollDecimals := 3;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[2] do begin with ParserTestData[2] do begin
@ -72,6 +81,9 @@ begin
SollNumFormat := nfFixedTh; SollNumFormat := nfFixedTh;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 3; SollDecimals := 3;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[3] do begin with ParserTestData[3] do begin
@ -80,6 +92,9 @@ begin
SollNumFormat := nfPercentage; SollNumFormat := nfPercentage;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 3; SollDecimals := 3;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[4] do begin with ParserTestData[4] do begin
@ -88,6 +103,9 @@ begin
SollNumFormat := nfLongTime; SollNumFormat := nfLongTime;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 0; SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[5] do begin with ParserTestData[5] do begin
@ -96,32 +114,66 @@ begin
SollNumFormat := nfLongTimeAM; SollNumFormat := nfLongTimeAM;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 0; SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[6] do begin with ParserTestData[6] do begin
FormatString := '[$-409]hh:mm:ss\ AM/PM;@'; FormatString := '[$-409]hh:mm:ss\ AM/PM;@';
SollFormatString := 'hh:mm:ss AM/PM'; SollFormatString := 'hh:mm:ss\ AM/PM;@';
SollNumFormat := nfLongTimeAM; SollNumFormat := nfCustom;
SollSectionCount := 2; SollSectionCount := 2;
SollDecimals := 0; SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[7] do begin with ParserTestData[7] do begin
FormatString := '[$-F400]dd.mm.yy\ hh:mm'; FormatString := '[$-F400]dd.mm.yy\ hh:mm';
SollFormatString := 'dd.mm.yy hh:mm'; SollFormatString := 'DD.MM.YY\ hh:mm';
SollNumFormat := nfShortDateTime; SollNumFormat := nfCustom;
SollSectionCount := 1; SollSectionCount := 1;
SollDecimals := 0; SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := ''; SollCurrencySymbol := '';
end; end;
with ParserTestData[8] do begin with ParserTestData[8] do begin
FormatString := '[$€] #,##0.00;-[$€] #,##0.00;{$€} 0.00'; FormatString := '[$€] #,##0.00;-[$€] #,##0.00;[$€] 0.00';
SollFormatString := '"€" #,##0.00;-"€" #,##0.00;"€" 0.00'; SollFormatString := '[$€] #,##0.00;-[$€] #,##0.00;[$€] 0.00';
SollNumFormat := nfCurrency; SollNumFormat := nfCurrency;
SollSectionCount := 3; SollSectionCount := 3;
SollDecimals := 2; SollDecimals := 2;
SollFactor := 0;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := '€'; SollCurrencySymbol := '€';
end; end;
with ParserTestData[9] do begin
FormatString := '0.00,,';
SollFormatString := '0.00,,';
SollNumFormat := nfCustom;
SollSectionCount := 1;
SollDecimals := 2;
SollFactor := 1e-6;
SollNumeratorDigits := 0;
SollDenominatorDigits := 0;
SollCurrencySymbol := '';
end;
with ParserTestData[10] do begin
FormatString := '# ??/??';
SollFormatString := '# ??/??';
SollNumFormat := nfFraction;
SollSectionCount := 1;
SollDecimals := 0;
SollFactor := 0;
SollNumeratorDigits := 2;
SollDenominatorDigits := 2;
SollCurrencySymbol := '';
end;
{ {
with ParserTestData[5] do begin with ParserTestData[5] do begin
FormatString := '#,##0.00 "$";-#,##0.00 "$";-'; FormatString := '#,##0.00 "$";-#,##0.00 "$";-';
@ -167,21 +219,28 @@ var
begin begin
MyWorkbook := TsWorkbook.Create; // needed to provide the FormatSettings for the parser MyWorkbook := TsWorkbook.Create; // needed to provide the FormatSettings for the parser
try try
for i:=0 to 5 do begin for i:=0 to High(ParserTestData) do begin
parser := TsNumFormatParser.Create(MyWorkbook, ParserTestData[i].FormatString); parser := TsNumFormatParser.Create(MyWorkbook, ParserTestData[i].FormatString);
try try
actual := parser.FormatString; actual := parser.FormatString;
CheckEquals(ParserTestData[i].SollFormatString, actual, CheckEquals(ParserTestData[i].SollFormatString, actual,
'Test format string ' + ParserTestData[i].SollFormatString + ' construction mismatch'); 'Test format string ' + ParserTestData[i].SollFormatString + ' construction mismatch');
CheckEquals(ord(ParserTestData[i].SollNumFormat), ord(parser.ParsedSections[0].NumFormat), CheckEquals(
'Test format (' + GetEnumName(TypeInfo(TsNumberFormat), integer(ParserTestData[i].SollNumFormat)) + GetEnumName(TypeInfo(TsNumberFormat), ord(ParserTestData[i].SollNumFormat)),
') detection mismatch'); GetEnumName(TypeInfo(TsNumberformat), ord(parser.ParsedSections[0].NumFormat)),
'Test format (' + ParserTestData[i].FormatString + ') detection mismatch');
CheckEquals(ParserTestData[i].SollDecimals, parser.ParsedSections[0].Decimals, CheckEquals(ParserTestData[i].SollDecimals, parser.ParsedSections[0].Decimals,
'Test format (' + ParserTestData[i].FormatString + ') decimal detection mismatch'); 'Test format (' + ParserTestData[i].FormatString + ') decimal detection mismatch');
CheckEquals(ParserTestData[i].SollCurrencySymbol, parser.ParsedSections[0].CurrencySymbol, CheckEquals(ParserTestData[i].SollCurrencySymbol, parser.ParsedSections[0].CurrencySymbol,
'Test format (' + ParserTestData[i].FormatString + ') currency symbol detection mismatch'); 'Test format (' + ParserTestData[i].FormatString + ') currency symbol detection mismatch');
CheckEquals(ParserTestData[i].SollSectionCount, parser.ParsedSectionCount, CheckEquals(ParserTestData[i].SollSectionCount, parser.ParsedSectionCount,
'Test format (' + ParserTestData[i].FormatString + ') section count mismatch'); 'Test format (' + ParserTestData[i].FormatString + ') section count mismatch');
CheckEquals(ParserTestData[i].SollFactor, parser.ParsedSections[0].Factor,
'Test format (' + ParserTestData[i].FormatString + ') factor mismatch');
CheckEquals(ParserTestData[i].SollNumeratorDigits, parser.ParsedSections[0].FracNumerator,
'Test format (' + ParserTestData[i].FormatString + ') numerator digits mismatch');
CheckEquals(ParserTestData[i].SollDenominatorDigits, parser.ParsedSections[0].FracDenominator,
'Test format (' + ParserTestData[i].FormatString + ') denominator digits mismatch');
finally finally
parser.Free; parser.Free;
end; end;