1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
unit PGN;
interface
uses
SysUtils, Classes;
type
TGroupIndex = 1..6;
TChessGame = class
tags: TStringList;
moves: array of array[TGroupIndex] of string;
termination: string;
constructor Create; overload;
destructor Destroy; override;
end;
TChessGameArray = array of TChessGame;
function ParsePGNText(aText: string): TChessGameArray;
implementation
uses
RegExpr;
constructor TChessGame.Create;
begin
inherited;
tags := TStringList.Create;
end;
destructor TChessGame.Destroy;
begin
tags.Free;
SetLength(moves, 0);
inherited;
end;
function ParsePGNText(aText: string): TChessGameArray;
const
COLUMN = '[a-h]';
ROW = '[1-8]';
KINGSIDE_CASTLING = 'O-O';
QUEENSIDE_CASTLING = 'O-O-O';
PIECE = '[PNBRQK]';
DISAMBIGUATION = COLUMN + '|' + ROW + '|' + COLUMN + ROW;
CAPTURE = 'x';
SQUARE_OR_CASTLING = COLUMN + ROW + '|' + QUEENSIDE_CASTLING + '|' + KINGSIDE_CASTLING;
PROMOTION = '=[NBRQ]';
CHECK_OR_CHECKMATE = '[+#]';
SAN_MOVE =
'(' + PIECE + ')?' +
'(' + DISAMBIGUATION + ')?' +
'(' + CAPTURE + ')?' +
'(' + SQUARE_OR_CASTLING + ')' +
'(' + PROMOTION + ')?' +
'(' + CHECK_OR_CHECKMATE + ')?';
FULL_MOVE = '(\d+)\.\s+(' + SAN_MOVE + '\s+){1,2}';
MOVES_SECTION = '(' + FULL_MOVE + ')+';
TAG_PAIR = '\[(\w+)\s+"([^"]+)"\]';
TAG_PAIRS_SECTION = '(' + TAG_PAIR + '\s+)+';
GAME_TERMINATION = '(1-0|0-1|1/2-1/2|\*)';
GAME = TAG_PAIRS_SECTION + MOVES_SECTION + GAME_TERMINATION;
type
TSearch = (searchGame, searchTagPair, searchFullMove, searchTermination, searchMove);
const
PATTERNS: array[TSearch] of string = (GAME, TAG_PAIR, FULL_MOVE, GAME_TERMINATION, SAN_MOVE);
var
vExpr: array[TSearch] of TRegExpr;
vSearch: TSearch;
vText: string;
procedure ParseFullMove(const aFullMove: string);
var
vIndex: integer;
begin
with vExpr[searchMove] do
if Exec(aFullMove) then
with result[High(result)] do
repeat
SetLength(moves, Succ(Length(moves)));
for vIndex := 1 to SubExprMatchCount do
moves[High(moves)][vIndex] := Match[vIndex];
until not ExecNext;
end;
begin
for vSearch in TSearch do
vExpr[vSearch] := TRegExpr.Create(PATTERNS[vSearch]);
SetLength(result, 0);
try
if vExpr[searchGame].Exec(aText) then
repeat
aText := vExpr[searchGame].Match[0];
SetLength(result, Succ(Length(result)));
result[High(result)] := TChessGame.Create;
result[High(result)].tags.Sorted := TRUE;
with vExpr[searchTagPair] do
if Exec(aText) then
repeat
result[High(result)].tags.Append(Format('%s=%s', [Match[1], Match[2]]));
until not ExecNext;
with vExpr[searchFullMove] do
if Exec(aText) then
repeat
ParseFullMove(Match[0]);
until not ExecNext;
with vExpr[searchTermination] do
if Exec(aText) then
result[High(result)].termination := Match[0];
until not vExpr[searchGame].ExecNext;
finally
for vSearch in TSearch do
vExpr[vSearch].Free;
end;
end;
end. |
Partager