unit referee_wedstrijd_sheet;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LazUTF8;
type
TStr = (sBlank, sTeamA, sTeamB, sPeriode1, sPeriode2, sPeriode3, sPeriode4, sScoring, sPEN, sMin);
TTeamStr = sTeamA..sTeamB;
TPeriodStr = sPeriode1..sPeriode4;
TParseDataStr = sTeamA..sPeriode4;
TStringsByDataStr = array[TParseDataStr] of String;
TPenaltyKind = (pkMinor, pkMajor, pkMisc, pkGMP, pkMP, pkPS);
TPenaltyValues = array[TPenaltyKind] of Integer;
TPeriodPenValues = array[TPeriodStr] of TPenaltyValues;
TTeamPeriodPenArray = array[TTeamStr] of TPeriodPenValues;
{ TWedstrijdSheetParser }
TWedstrijdSheetParser = class(TObject)
private
FFilename: String;
FStringsByData: TStringsByDataStr;
function GetTeamA: String;
function GetTeamB: String;
function HasStr(const aLine: String; aStr: TStr; out aPos: Integer): Boolean;
function ReadFileToArrayOK: Boolean;
public
DataArray: TTeamPeriodPenArray;
constructor Create(const aFilename: String);
property Filename: String read FFilename;
property TeamA: String read GetTeamA;
property TeamB: String read GetTeamB;
end;
implementation
{ TWedstrijdSheetParser }
function TWedstrijdSheetParser.GetTeamA: String;
begin
Exit(FStringsByData[sTeamA]);
end;
function TWedstrijdSheetParser.GetTeamB: String;
begin
Exit(FStringsByData[sTeamB]);
end;
function TWedstrijdSheetParser.HasStr(const aLine: String; aStr: TStr; out aPos: Integer): Boolean;
begin
aPos := 0;
case aLine of
'': Exit(False);
else case aStr of
sBlank: Exit(False);
sTeamA: begin aPos := Pos('Team A:', aLine); Exit(aPos > 0); end;
sTeamB: begin aPos := Pos('Team B:', aLine); Exit(aPos > 0); end;
sPeriode1: begin aPos := Pos('1e periode', aLine); Exit(aPos > 0); end;
sPeriode2: begin aPos := Pos('2e periode', aLine); Exit(aPos > 0); end;
sPeriode3: begin aPos := Pos('3e periode', aLine); Exit(aPos > 0); end;
sPeriode4: begin aPos := Pos('Verlenging', aLine); Exit(aPos > 0); end;
sScoring: begin aPos := Pos('Scoring', aLine); Exit(aPos > 0); end;
sPEN: begin aPos := Pos(' PEN ', aLine); Exit(aPos > 0); end;
sMin: begin aPos := Pos(' min ', aLine); Exit(aPos > 0); end;
end;
end;
end;
function TWedstrijdSheetParser.ReadFileToArrayOK: Boolean;
var
tf: TextFile;
tmp: String;
s: TStr;
allPeriodsRead: Boolean;
p: Integer;
begin
Result := False;
allPeriodsRead := False;
{$I-}
AssignFile(tf, FFilename);
s := sBlank;
try
Reset(tf);
while not EOF(tf) do
begin
ReadLn(tf, tmp);
UTF8FixBroken(tmp);
tmp := Trim(tmp);
if tmp = '' then
Continue;
case s of
sBlank, sPEN: ;
sTeamA: begin FStringsByData[sTeamA] := tmp; s := sBlank; end;
sTeamB: begin FStringsByData[sTeamB] := tmp; s := sBlank; end;
sPeriode1: case HasStr(tmp, sScoring, p) of
True: begin s := sBlank; Continue; end;
False: if HasStr(tmp, sPEN, p) then
FStringsByData[sPeriode1] := FStringsByData[sPeriode1] + Copy(tmp, p+5, Maxint) + ',';
end;
sPeriode2: case HasStr(tmp, sScoring, p) of
True: begin s := sBlank; Continue; end;
False: if HasStr(tmp, sPEN, p) then
FStringsByData[sPeriode2] := FStringsByData[sPeriode2] + Copy(tmp, p+5, MaxInt) + ',';
end;
sPeriode3: case HasStr(tmp, sScoring, p) of
True: begin s := sBlank; Continue; end;
False: if HasStr(tmp, sPEN, p) then
FStringsByData[sPeriode3] := FStringsByData[sPeriode3] + Copy(tmp, p+5, MaxInt) + ',';
end;
sPeriode4: case HasStr(tmp, sScoring, p) of
True: begin s := sBlank; allPeriodsRead := True; Continue; end;
False: if HasStr(tmp, sPEN, p) then
FStringsByData[sPeriode4] := FStringsByData[sPeriode4] + Copy(tmp, p+5, MaxInt) + ',';
end;
sScoring: if allPeriodsRead then
Break;
end;
if s = sBlank then
begin
if HasStr(tmp, sTeamA, p) then
s := sTeamA
else if HasStr(tmp, sTeamB, p) then
s := sTeamB
else if HasStr(tmp, sPeriode1, p) then
s := sPeriode1
else if HasStr(tmp, sPeriode2, p) then
s := sPeriode2
else if HasStr(tmp, sPeriode3, p) then
s := sPeriode3
else if HasStr(tmp, sPeriode4, p) then
s := sPeriode4
else if HasStr(tmp, sScoring, p) then
s := sScoring;
end;
end; // while not EOF
finally
CloseFile(tf);
end;
{$I+}
Result := IOResult = 0;
end;
constructor TWedstrijdSheetParser.Create(const aFilename: String);
var
pds: TParseDataStr;
sl: TStringList;
teemA, teemB, s: String;
team: TTeamStr;
penKind: TPenaltyKind;
procedure ParsePenStr(out aTeam: TTeamStr; out aPenKind: TPenaltyKind);
var
p: Integer;
si: String;
begin
if Pos(teamA, s) > 0 then
aTeam := sTeamA
else if Pos(teamB, s) > 0 then
aTeam := sTeamB
else Assert(True,'Error in parsing team name or error in data');
case HasStr(s, sMin, p) of
True: begin
Dec(p);
si := s[p];
Dec(p);
while s[p] in ['0'..'9'] do
begin
si := s[p] + si;
Dec(p);
end;
Assert(TryStrToInt(si, p),'Error in parsing minute value');
case si of
'2': aPenKind := pkMinor;
'5': aPenKind := pkMajor;
'10': aPenKind := pkMisc;
'20': aPenKind := pkGMP;
'25': aPenKind := pkMP;
'50': aPenKind := pkPS;
else Assert(True,'Error: "min" has unexpected value "'+si+'"');
end;
end;
False: aPenKind := pkPS;
end;
end;
begin
Assert(FileExists(aFilename),'TWedstrijdSheetParser.Create: file '+aFilename+' cannot be found');
FFilename := aFilename;
Assert(ReadFileToArrayOK,'TWedstrijdSheetParser.Create: failed to create array from '+aFilename);
teemA := FStringsByData[sTeamA];
teemB := FStringsByData[sTeamB];
sl := TStringList.Create;
sl.StrictDelimiter := True;
for pds := Low(TPeriodStr) to High(TPeriodStr) do
begin
sl.CommaText := FStringsByData[pds];
for s in sl do
if s <> '' then
begin
ParsePenStr(team, penKind);
Inc(DataArray[team][pds][penKind]);
end;
end;
sl.Free;
end; // Create
end.