To illustrate the utility of regular expressions, here are some example functions for this problem. pgn2array will turn a string containing PGN formatted pairs into an associative array.
PHP Code:
function parseName($name) {
preg_match('/^(?:(\S+) (?:(.*) )?)?(\S+)$/', $name, $name);
return array_combine( array('full', 'first', 'middle', 'last'), $name);
}
function parseDate($date) {
return array_combine(array('year', 'month', 'day'), explode('.', $date));
}
function pgn2array($pgn) {
static $filters = array('white' => 'parseName', 'black' => 'parseName',
'date' => 'parseDate', 'eventdate' => 'parseDate');
$arr=False;
if (preg_match_all('/\[(\w+) "([^"]+)"\]/', $pgn, $matches, PREG_PATTERN_ORDER)) {
$arr = array_combine(array_map('strtolower', $matches[1]), $matches[2]);
foreach ($filters as $key => $filter) {
$arr[$key] = call_user_func($filter, $arr[$key]);
}
}
return $arr;
}
If the data is stored in a file, the above would require you to read the whole file before parsing it. To parse a file in place, try:
PHP Code:
function filterTagPair($key, $value) {
switch($key) {
case 'white':
case 'black':
return parseName($value);
break;
case 'date':
case 'eventdate':
return parseDate($value);
break;
}
return $value;
}
function pgnFile2array($file) {
$arr = array();
$fpos = ftell($file);
while (!feof($file) && $line=fgets($file)) {
if (preg_match('/\[(\w+) "([^"]+)"\]/', $line, $matches)) {
$matches[1] = strtolower($matches[1]);
$matches[2] = filterTagPair($matches[1], $matches[2]);
$arr[$matches[1]] = $matches[2];
$fpos = ftell($file);
} else {
fseek($file, $fpos);
break;
}
}
return count($arr) ? $arr : False;
}
Looping over an array of filters (as pgn2array does) would work just as well for pgnFile2array. I used a switch to illustrate another approach.
None of the above deals with errors, so they could be fleshed out in this regard.