Improvements for a parser function?
Posted: 11 May 2015 10:00
I want to parse the content of matching brackets in a serialized string (brackets are nested inside each other).
It isn't finished yet (I will add the "count" option and it will return an empty string if the $lvl variable is greater than the number of existing matching brackets).
This is the current code:
It's necessary to skip brackets that aren't valid because they are placed in matching quotation marks.
It's currently called with:
With e.g.:
E.g. getSerializedData($a, 4) takes between 350 - 400 msecs.
Is there a clever way to speed the whole thing up?
It isn't finished yet (I will add the "count" option and it will return an empty string if the $lvl variable is greater than the number of existing matching brackets).
This is the current code:
Code: Select all
function getSerializedData($str, $lvl = 1, $pattern = '{|}') {
if !($str) { return 'Error: $str is empty!'; }
if !($lvl) { return 'Error: $lvl must be >= 1 or "count"!'; }
// if !(isBalanced($str)) { return 'Error: $str does not contain serialized data!'; }
if (!$pattern || !regexmatches($pattern, "\|")) { return 'Error: $pattern syntax is invalid!'; }
$fToken = gettoken($pattern, 1, "|"); // First Token
$sToken = gettoken($pattern, 2, "|"); // Second Token
$lvlCount = ($lvl LikeI "count") ? 1 : 0; // Return number of occurrences instead of real data
$fPos = 0;
$skipNext = 0;
while ($i++ < $lvl) {
$j = 1;
while ($j <= strlen($str)) {
$c = substr($str, $j - 1, 1);
if ($fPos) { // We already found the first valid opening token
if ($c == $fToken) { $skipNext++; } // Another opening token -> Increase skip counter
elseif ($c == $sToken) {
if ($skipNext) { $skipNext--; } // Decrease skip counter
else { $str = substr($str, $fPos + 1, $j - $fPos - 2); $fPos = 0; } // Reset first position!
}
} else {
if ($c == $fToken) { // Find the first valid opening token
if (gettoken(regexmatches(substr($str, $fPos, $j - 1), '"'), "count", "|") % 2) { $fPos = 0; } // Unbalanced -> Skip it
else { $fPos = $j - 1; }
}
}
$j++;
}
}
return $str;
}
It's currently called with:
Code: Select all
$start = now("msecs");
$b = getSerializedData($a); // ''
$duration = now("msecs") - $start;
text "$b<crlf 2>Time: $duration";It returns correct results e.g.:$a = 'a:1:{s:9:"@test.bat {a}";a:1:{s:24:"AJXP_METADATA_SHAREDUSER";a:1:{s:10:"users_meta";a:1:{s:4:"tags";s:20:"batch file {new tag}";}}}}';
$a = 'a{b{c{d{f{g}}}}}';
$a = 'a"{}"b{c}';
My "problem". Because it traverses the string character by character the execution can slow down quite a bit.getSerializedData($a, 1) -> {s:9:"@test.bat {a}";a:1:{s:24:"AJXP_METADATA_SHAREDUSER";a:1:{s:10:"users_meta";a:1:{s:4:"tags";s:20:"batch file {new tag}";}}}}
getSerializedData($a, 2) -> {s:24:"AJXP_METADATA_SHAREDUSER";a:1:{s:10:"users_meta";a:1:{s:4:"tags";s:20:"batch file {new tag}";}}}
getSerializedData($a, 3) -> {s:10:"users_meta";a:1:{s:4:"tags";s:20:"batch file {new tag}";}}
getSerializedData($a, 4) -> {s:4:"tags";s:20:"batch file {new tag}";}
(not yet implemented) getSerializedData($a, 5) -> "" // "new tag" is not a valid match because the brackets are inside quotation marks
E.g. getSerializedData($a, 4) takes between 350 - 400 msecs.
Is there a clever way to speed the whole thing up?