Help with regular expression and nested items
I have a class structure in PHP which I am using to allow for varying calculations of an average of marks in a teacher's markbook. I am attempting to make this as flexible as possible...
Each Assessment
(A) has a mark and a weighting to count to the overall average. This object has getMark
and getWeighting
methods which allows be to extract the mark and the weighting.
The Assessment
class is extended to create a WeightedAverage
(W) object which can store many assessments. It includes an array of assessments in addition to the mark (which is unused) and the weighting. The getMark
method is overridden to calculate a mark using the array of Ass开发者_运维百科essment
objects (which, by nature of the OO employed, could include other weighted averages).
Finally, the Assessment
class is extended to create a TopX
(T) object which can store many assessments and return the average of the top 'X' assessments stored in it.
I now need to store the "algorithm" that the teacher wants to use in a database. I envisage storing it as a string that might look like this:
W(A(1,10),A(2,10),A(3,10),T(3,30,A(4,1),A(5,1),A(6,1),A(7,1),W(A(8,1),A(9,1))))
Ideally, I'd like to end up with an array that looks something like this which can then easily be translated into the objects required for the calculation.
$array [0] ['type'] = 'W'
$array [0] [0] = 'A(1,10)'
$array [0] [1] = 'A(2,10)'
$array [0] [2] = 'A(3,10)'
$array [0] [3] ['type'] = 'T'
$array [0] [3] ['params'] = '3,30'
$array [0] [3] [0] = 'A(4,1)'
$array [0] [3] [1] = 'A(5,1)'
$array [0] [3] [2] = 'A(6,1)'
$array [0] [3] [3] = 'A(7,1)'
$array [0] [3] [4] ['type'] = 'W'
$array [0] [3] [4] [0] = 'A(8,1)'
$array [0] [3] [4] [1] = 'A(9,1)'
I don't know if regular expressions are the way forward here, or whether this will require some hefty coding....
Please feel free to suggest other solutions to the problem. For now, this is still in the planning phase!
You need a simplistic parser. But I would use a regular expression still to split up the tokens more easily (otherwise you wold have more work with string functions).
$str = 'W(A(1,10),A(2,10),A(3,10),T(3,30,A(4,1),A(5,1),A(6,1),A(7,1),W(A(8,1),A(9,1))))';
preg_match_all('/[AWT()]|\d+/', $str, $token);
print_r(group($token[0]));
function group(&$t, $type="ROOT") {
$data["type"] = $type;
while ($token = array_shift($t)) {
switch ($token) {
case "A": case "W": case "T":
$type = $token;
break;
case "(":
$d = group($t, $type);
$data[] = $d;
// or $data[] = $type=="A" ? "A(".implode(",",array_slice($d,1)).")" : $d;
break;
case ")":
return $data;
default:
$data[] = $token;
}
}
return $data;
}
It doesn't give quite the result that you wanted. It splits up each group according to the simplistic rules:
Array
(
[type] => ROOT
[0] => Array
(
[type] => W
[0] => Array
(
[type] => A
[0] => 1
[1] => 10
)
[1] => Array
(
[type] => A
[0] => 2
[1] => 10
)
[2] => Array
(
[type] => A
[0] => 3
[1] => 10
)
[3] => Array
(
[type] => T
[0] => 3
[1] => 30
[2] => Array
(
[type] => A
[0] => 4
[1] => 1
)
[3] => Array
(
[type] => A
[0] => 5
[1] => 1
)
[4] => Array
(
[type] => A
[0] => 6
[1] => 1
)
[5] => Array
(
[type] => A
[0] => 7
[1] => 1
)
[6] => Array
(
[type] => W
[0] => Array
(
[type] => A
[0] => 8
[1] => 1
)
[1] => Array
(
[type] => A
[0] => 9
[1] => 1
)
)
)
)
)
So you might actually have to travers it again, and compact the A
groups again into strings. But that seems easy enough.
Or see the commented out one-liner which folds the A(x,y) tokens again:
Array
(
[type] => ROOT
[0] => Array
(
[type] => W
[0] => A(1,10)
[1] => A(2,10)
[2] => A(3,10)
[3] => Array
(
[type] => T
[0] => 3
[1] => 30
[2] => A(4,1)
[3] => A(5,1)
[4] => A(6,1)
[5] => A(7,1)
[6] => Array
(
[type] => W
[0] => A(8,1)
[1] => A(9,1)
)
)
)
)
精彩评论