Find answer to string equation without using eval() - php

I need a way of taking an equation given as a string and finding it's mathematical answer, the big caveat is that I can't use eval().
I know the equation will only ever contain numbers, the four mathematical operators (i.e. * / + -) and parentheses, it may or may not have spaces in the string. Here's a couple of examples.
4 * 4
4+6/3
(3 / 2)*(4+8)
(4+8) * 2
I'm guessing that it's going to have to be done with some kind of regex?

Math expressions aren't regular. They're context-free.
Your best bet is to parse them using well-known math parsing algorithms like the shunting yard algorithm. All you have to worry about is implementing the algorithm in PHP. You might even be able to find PHP implementations of it online.

Just in case anybody's interested here is the algorithm I came up with in PHP for producing Reverse Polish Notation
function convertToRPN($equation)
{
$equation = str_replace(' ', '', $equation);
$tokens = token_get_all('<?php ' . $equation);
$operators = array('*' => 1, '/' => 1, '+' => 2, '-' => 2);
$rpn = '';
$stack = array();
$size = count($tokens);
for($i = 1; $i < $size; $i++) {
if(is_array($tokens[$i])) {
$rpn .= $tokens[$i][1] . ' ';
} else {
if(empty($stack) || $tokens[$i] == '(') {
$stack[] = $tokens[$i];
} else {
if($tokens[$i] == ')') {
while(end($stack) != '(') {
$rpn .= array_pop($stack);
}
array_pop($stack);
} else {
while(!empty($stack) && end($stack) != '(' && $operators[$tokens[$i]] >= $operators[end($stack)]) {
$rpn .= array_pop($stack);
}
$stack[] = $tokens[$i];
}
}
}
}
while(!empty($stack)) {
$rpn .= array_pop($stack);
}
return $rpn;
}

Related

I cannot use a given symbol in the char type, as a mathematical symbol [duplicate]

I want to calculate math expression from a string. I have read that the solution to this is to use eval(). But when I try to run the following code:
<?php
$ma ="2+10";
$p = eval($ma);
print $p;
?>
It gives me the following error:
Parse error: syntax error, unexpected $end in
C:\xampp\htdocs\eclipseWorkspaceWebDev\MandatoryHandinSite\tester.php(4)
: eval()'d code on line 1
Does someone know the solution to this problem.
While I don't suggest using eval for this (it is not the solution), the problem is that eval expects complete lines of code, not just fragments.
$ma ="2+10";
$p = eval('return '.$ma.';');
print $p;
Should do what you want.
A better solution would be to write a tokenizer/parser for your math expression. Here's a very simple regex-based one to give you an example:
$ma = "2+10";
if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $ma, $matches) !== FALSE){
$operator = $matches[2];
switch($operator){
case '+':
$p = $matches[1] + $matches[3];
break;
case '-':
$p = $matches[1] - $matches[3];
break;
case '*':
$p = $matches[1] * $matches[3];
break;
case '/':
$p = $matches[1] / $matches[3];
break;
}
echo $p;
}
Take a look at this..
I use this in an accounting system where you can write math expressions in amount input fields..
Examples
$Cal = new Field_calculate();
$result = $Cal->calculate('5+7'); // 12
$result = $Cal->calculate('(5+9)*5'); // 70
$result = $Cal->calculate('(10.2+0.5*(2-0.4))*2+(2.1*4)'); // 30.4
Code
class Field_calculate {
const PATTERN = '/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/';
const PARENTHESIS_DEPTH = 10;
public function calculate($input){
if(strpos($input, '+') != null || strpos($input, '-') != null || strpos($input, '/') != null || strpos($input, '*') != null){
// Remove white spaces and invalid math chars
$input = str_replace(',', '.', $input);
$input = preg_replace('[^0-9\.\+\-\*\/\(\)]', '', $input);
// Calculate each of the parenthesis from the top
$i = 0;
while(strpos($input, '(') || strpos($input, ')')){
$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'self::callback', $input);
$i++;
if($i > self::PARENTHESIS_DEPTH){
break;
}
}
// Calculate the result
if(preg_match(self::PATTERN, $input, $match)){
return $this->compute($match[0]);
}
// To handle the special case of expressions surrounded by global parenthesis like "(1+1)"
if(is_numeric($input)){
return $input;
}
return 0;
}
return $input;
}
private function compute($input){
$compute = create_function('', 'return '.$input.';');
return 0 + $compute();
}
private function callback($input){
if(is_numeric($input[1])){
return $input[1];
}
elseif(preg_match(self::PATTERN, $input[1], $match)){
return $this->compute($match[0]);
}
return 0;
}
}
I recently created a PHP package that provides a math_eval helper function. It does exactly what you need, without the need to use the potentially unsafe eval function.
You just pass in the string version of the mathematical expression and it returns the result.
$two = math_eval('1 + 1');
$three = math_eval('5 - 2');
$ten = math_eval('2 * 5');
$four = math_eval('8 / 2');
You can also pass in variables, which will be substituted if needed.
$ten = math_eval('a + b', ['a' => 7, 'b' => 3]);
$fifteen = math_eval('x * y', ['x' => 3, 'y' => 5]);
Link: https://github.com/langleyfoxall/math_eval
Using eval function is very dangerous when you can't control the string argument.
Try Matex for safe Mathematical formulas calculation.
Solved!
<?php
function evalmath($equation)
{
$result = 0;
// sanitize imput
$equation = preg_replace("/[^a-z0-9+\-.*\/()%]/","",$equation);
// convert alphabet to $variabel
$equation = preg_replace("/([a-z])+/i", "\$$0", $equation);
// convert percentages to decimal
$equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation);
$equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation);
$equation = preg_replace("/([0-9]{1})(%)/",".0\$1",$equation);
$equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation);
if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;
// return $equation;
}
$a = 2;
$b = 3;
$c = 5;
$f1 = "a*b+c";
$f1 = str_replace("a", $a, $f1);
$f1 = str_replace("b", $b, $f1);
$f1 = str_replace("c", $c, $f1);
evalmath($f1);
/*if ( $equation != "" ){
$result = #eval("return " . $equation . ";" );
}
if ($result == null) {
throw new Exception("Unable to calculate equation");
}
echo $result;*/
?>
This method has two major drawbacks:
Security, php script is being evaluated by the eval function. This is bad,
especially when the user wants to inject malicious code.
Complexity
I created this, check it out: Formula Interpreter
How does it work ?
First, create an instance of FormulaInterpreter with the formula and its parameters
$formulaInterpreter = new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]);
Use the execute() method to interpret the formula. It will return the result:
echo $formulaInterpreter->execute();
in a single line
echo (new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]))->execute();
Examples
# Formula: speed = distance / time
$speed = (new FormulaInterpreter("distance/time", ["distance" => 338, "time" => 5]))->execute() ;
echo $speed;
#Venezuela night overtime (ordinary_work_day in hours): (normal_salary * days_in_a_work_month)/ordinary_work_day
$parameters = ["normal_salary" => 21000, "days_in_a_work_month" => 30, "ordinary_work_day" => 8];
$venezuelaLOTTTArt118NightOvertime = (new FormulaInterpreter("(normal_salary/days_in_a_work_month)/ordinary_work_day", $parameters))->execute();
echo $venezuelaLOTTTArt118NightOvertime;
#cicle area
$cicleArea = (new FormulaInterpreter("3.1416*(radio*radio)", ["radio" => 10]))->execute();
echo $cicleArea;
About the formulas
It must contain at least two operands and an operator.
Operands' name could be in upper or lower case.
By now, math functions as sin, cos, pow… are not included. I'm working to include them.
If your formula is not valid, you will get an error message like: Error, your formula (single_variable) is not valid.
Parameters' values must be numeric.
You can improve it if you want to!
eval Evaluates the given code as PHP. Meaning that it will execute the given paremeter as a PHP piece of code.
To correct your code, use this :
$ma ="print (2+10);";
eval($ma);
Using eval function
protected function getStringArthmeticOperation($value, $deduct)
{
if($value > 0){
$operator = '-';
}else{
$operator = '+';
}
$mathStr = '$value $operator $deduct';
eval("\$mathStr = \"$mathStr\";");
$userAvailableUl = eval('return '.$mathStr.';');
return $userAvailableUl;
}
$this->getStringArthmeticOperation(3, 1); //2
Finding a sweetspot between the dangers of eval and the limitless calculation possibilities I suggest checking the input for only numbers, operators and brackets:
if (preg_match('/^[0-9\+\-\*\/\(\)\.]+$/', $mathString)) {
$value = eval('return
' . $mathString . ';');
} else {
throw new \Exception('Invalid calc() value: ' . $mathString);
}
It's still easy to use yet relatively save. And it can handle any basic math calulation like (10*(1+0,2)) which isn't possible with most of the mentioned solutions here.
An eval'd expression should end with ";"
Try this :
$ma ="2+10;";
$p = eval($ma);
print $p;
By the way, this is out of scope but the 'eval' function won't return the value of the expression. eval('2+10') won't return 12.
If you want it to return 12, you should eval('return 2+10;');

PHP - latex format of function with regex

Is it possible to write a regex which would take input like 'sqrt(2 * (2+2)) + sin(pi/6)' and transform it into '\sqrt{2 \cdot (2+2)} + \sin(\pi/6)'?
The problem is the 'sqrt' and parentheses in it. It is obvious I can't simply use something like this:
/sqrt\((.?)\)/ -> \\sqrt{$1}
because this code would create something like this '\sqrt{2 \cdot (2+2)) + \sin(\pi/6}'.
My solution: it simply go throw the string converted to char array and tests if a current substring starts with $latex, if it does second for-cycle go from this point in different direction and by parentheses decides where the function starts and ends. (startsWith function)
Code:
public static function formatFunction($function, $latex, $input) {
$input = preg_replace("/" . $function . "\(/", $latex . "{", $input);
$arr = str_split($input);
$inGap = false;
$gap = 0;
for ($i = count($arr) - 1; $i >= 0; $i--) {
if (startsWith(substr($input, $i), $latex)) {
for ($x = $i; $x < count($arr); $x++) {
if ($arr[$x] == "(" || $arr[$x] == "{") { $gap++; $inGap = true; }
else if ($arr[$x] == ")" || $arr[$x] == "}") { $gap--; }
if ($inGap && $gap == 0) {
$arr[$x] = "}";
$inGap = false;
break;
}
}
}
$gap = 0;
}
return implode($arr);
}
Use:
self::formatFunction("sqrt", "\\sqrt",
"sqrt(25 + sqrt(16 - sqrt(49)) + (7 + 1)) + sin(pi/2)");
Output:
\sqrt{25+\sqrt{16-\sqrt{49}}+(7+1)}+\sin (\pi/2)
Note: sin and pi aren't formated by this code, it's only str_replace function...
In general, no regular expression can effectively handle nested parentheses. Sorry to be the bearer of bad news! The MathJAX parser library can interpret LaTeX equations and you could probably add a custom output routine to do what you want.
For TeX questions, you can also try http://tex.stackexchange.com .
Some time ago i soved a similar problem in such way. Maybe it will be helpful for you
$str = 'sqrt((2 * (2+2)) + sin(pi/(6+7)))';
$from = []; // parentheses content
$to = []; // patterns for replace #<number>
$brackets = [['(', ')'], ['{', '}'], ['[', ']']]; // new parentheses for every level
$level = 0;
$count = 1; // count or replace made
while($count) {
$str = preg_replace_callback('(\(([^()]+)\))',
function ($m) use (&$to, &$from, $brackets, $level) {
array_unshift($to, $brackets[$level][0] . $m[1] . $brackets[$level][1]);
$i = '#' . (count($to)-1); // pattern for future replace.
// here it '#1', '#2'.
// Make it so they will be unique
array_unshift($from, $i);
return $i; }, $str, -1, $count);
$level++;
}
echo str_replace($from, $to, $str); // return content back
// sqrt[{2 * (2+2)} + sin{pi/(6+7)}]
I forgot all details, but it, seems, works

Rewrite a large number of for loops into something shorter

I have the following code:
for($a=1; $a<strlen($string); $a++){
for($b=1; $a+$b<strlen($string); $b++){
for($c=1; $a+$b+$c<strlen($string); $c++){
for($d=1; $a+$b+$c+$d<strlen($string); $d++){
$tempString = substr_replace($string, ".", $a, 0);
$tempString = substr_replace($tempString, ".", $a+$b+1, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+2, 0);
$tempString = substr_replace($tempString, ".", $a+$b+$c+$d+3, 0);
echo $tempString."</br>";
}
}
}
}
What it does is to make all possible combinatons of a string with several dots.
Example:
t.est123
te.st123
tes.t123
...
test12.3
Then, I add one more dot:
t.e.st123
t.es.t123
...
test1.2.3
Doing the way I'm doing now, I need to create lots and lots of for loops, each for a determined number of dots. I don't know how I can turn that example into a functon or other easier way of doing this.
Your problem is a combination problem. Note: I'm not a math freak, I only researched this information because of interest.
http://en.wikipedia.org/wiki/Combination#Number_of_k-combinations
Also known as n choose k. The Binomial coefficient is a function which gives you the number of combinations.
A function I found here: Calculate value of n choose k
function choose($n, $k) {
if ($k == 0) {return 1;}
return($n * choose($n - 1, $k - 1)) / $k;
}
// 6 positions between characters (test123), 4 dots
echo choose(6, 4); // 15 combinations
To get all combinations you also have to choose between different algorithms.
Good post: https://stackoverflow.com/a/127856/1948627
UPDATE:
I found a site with an algorithm in different programming languages. (But not PHP)
I've converted it to PHP:
function bitprint($u){
$s= [];
for($n= 0;$u > 0;++$n, $u>>= 1) {
if(($u & 1) > 0) $s[] = $n;
}
return $s;
}
function bitcount($u){
for($n= 0;$u > 0;++$n, $u&= ($u - 1));
return $n;
}
function comb($c, $n){
$s= [];
for($u= 0;$u < 1 << $n;$u++) {
if(bitcount($u) == $c) $s[] = bitprint($u);
}
return $s;
}
echo '<pre>';
print_r(comb(4, 6));
It outputs an array with all combinations (positions between the chars).
The next step is to replace the string with the dots:
$string = 'test123';
$sign = '.';
$combs = comb(4, 6);
// get all combinations (Th3lmuu90)
/*
$combs = [];
for($i=0; $i<strlen($string); $i++){
$combs = array_merge($combs, comb($i, strlen($string)-1));
}
*/
foreach ($combs as $comb) {
$a = $string;
for ($i = count($comb) - 1; $i >= 0; $i--) {
$a = substr_replace($a, $sign, $comb[$i] + 1, 0);
}
echo $a.'<br>';
}
// output:
t.e.s.t.123
t.e.s.t1.23
t.e.st.1.23
t.es.t.1.23
te.s.t.1.23
t.e.s.t12.3
t.e.st.12.3
t.es.t.12.3
te.s.t.12.3
t.e.st1.2.3
t.es.t1.2.3
te.s.t1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
This is quite an unusual question, but I can't help but try to wrap around what you are tying to do. My guess is that you want to see how many combinations of a string there are with a dot moving between characters, finally coming to rest right before the last character.
My understanding is you want a count and a printout of string similar to what you see here:
t.est
te.st
tes.t
t.es.t
te.s.t
t.e.s.t
count: 6
To facilitate this functionality I came up with a class, this way you could port it to other parts of code and it can handle multiple strings. The caveat here is the strings must be at least two characters and not contain a period. Here is the code for the class:
class DotCombos
{
public $combos;
private function combos($string)
{
$rebuilt = "";
$characters = str_split($string);
foreach($characters as $index => $char) {
if($index == 0 || $index == count($characters)) {
continue;
} else if(isset($characters[$index]) && $characters[$index] == ".") {
break;
} else {
$rebuilt = substr($string, 0, $index) . "." . substr($string, $index);
print("$rebuilt\n");
$this->combos++;
}
}
return $rebuilt;
}
public function allCombos($string)
{
if(strlen($string) < 2) {
return null;
}
$this->combos = 0;
for($i = 0; $i < count(str_split($string)) - 1; $i++) {
$string = $this->combos($string);
}
}
}
To make use of the class you would do this:
$combos = new DotCombos();
$combos->allCombos("test123");
print("Count: $combos->combos");
The output would be:
t.est123
te.st123
tes.t123
test.123
test1.23
test12.3
t.est12.3
te.st12.3
tes.t12.3
test.12.3
test1.2.3
t.est1.2.3
te.st1.2.3
tes.t1.2.3
test.1.2.3
t.est.1.2.3
te.st.1.2.3
tes.t.1.2.3
t.es.t.1.2.3
te.s.t.1.2.3
t.e.s.t.1.2.3
Count: 21
Hope that is what you are looking for (or at least helps)....

PHP find missing numbers in array of hyphenated numbers

I have an array of numbers, these numbers are sometimes hyphenated, à la software version numbers. What I'm trying to do is echo "Missing!" or run a specific function when a number is missing.
For example:
$numbers = array('1', '2', '3', '5', '6', '8');
Prints:
1
2
3
Missing!
5
6
Missing!
8
I'm running into problems with the hyphens.
For example:
$numbers = array('1', '1-1', '1-3', '3-1-1', '3-1-3');
Prints:
1
1-1
Missing!
1-3
Missing!
3-1-1
Missing!
3-1-3
Plus my code seems awfully long/doing too many things for what -- seems to me -- should be a simple task. Is there a method or algorithm for this sort of thing?
Here's my code:
<?php
$numbers = array(
'1',
'1-1',
'1-3',
'3-1-1',
'3-1-3'
);
foreach ($numbers as $number) {
if (isset($prev_number)) {
$curr_number = explode('-', $number);
$prev_levels = explode('-', $prev_number);
if (preg_match('/-/', $number) and !preg_match('/-/', $prev_number)) {
if (current() - $prev_levels[0] >= 1) {
echo 'Missing!<br>' . PHP_EOL;
}
}
for ($missing = 1; ((count($curr_number) - count($prev_levels)) - $missing) >= 1; $missing++) {
echo 'Missing!<br>' . PHP_EOL;
}
foreach ($curr_number as $hyphen => $part) {
for ($missing = 1; ($part - $missing) - $prev_levels[$hyphen] >= 1; $missing++) {
echo 'Missing!<br>' . PHP_EOL;
}
}
} else {
if ($number != '1') {
echo 'Missing!<br>' . PHP_EOL;
foreach ($curr_number as $part) {
for ($missing = 1; $part > $missing; $missing++) {
echo 'Missing!<br>' . PHP_EOL;
}
}
}
}
echo $number . '<br>' . PHP_EOL;
$prev_number = $number;
}
?>
Only a partial answer.
Plus my code seems awfully long/doing too many things for what -- seems to me -- should be a simple task.
Right observation. If it's doing too many things, try to split up the task into pieces. Modularize.
For example: I see 6 explode calls in your code. You constantly struggling with transforming the input into a usable data format. Do a pre-process stage, convert the strings into arrays with explode once, and then work on that data format.
You can iterate through the list and for each pair you attempt to reach the second by applying a transformation on the first:
Increase the last value, e.g. "1" becomes "2" and "1-1" becomes "1-2".
Add a new sub value, e.g. "1" becomes "1-1" and "1-1" becomes "1-1-1".
#1 can be expanded by increasing from right to left.
If none of the transformations match the number is considered missing. In code:
$numbers = array('1', '1-1', '1-2', '1-3', '3-1-1', '3-1-3');
$first = array_shift($numbers);
echo "$first\n";
while (($second = array_shift($numbers)) !== null) {
if (find_next($first, $second) === false) {
echo "Missing\n";
}
echo "$second\n";
$first = $second;
}
// attempt to transform between current and next
function find_next($current, $next)
{
if (increment_last($current) == $next) {
return $next; // first transformation worked
} elseif (add_suffix($current) == $next) {
return $next; // second transformation worked
}
return false; // nothing worked
}
// transformation 1
function increment_last($value)
{
if (($pos = strpos($value, '-')) !== false) {
$last = substr($value, $pos + 1) + 1;
return substr_replace($value, $last, $pos + 1, strlen($last));
} else {
return $value + 1;
}
}
// transformation 2
function add_suffix($value)
{
return "$value-1";
}
This is not an algorithm, but a heuristic; it does a best effort at doing what you want but there's no formal proof that it works.

Extract HTML-like tags with PHP

I'm trying to extract OUTERMOST special HTML-like tags from a given string. Here's a sample string:
sample string with <::Class id="some id\" and more">text with possible other tags inside<::/Class> some more text
I need to find where in a string a <::Tag starts and where it ends. The problem is it might contain nested tags inside. Is there a simple loop-like algorithm to find the FIRST ocurrence of the <::Tag and the length of the string until the matching <::/Tag>? I've tried a different way, using a simple HTML tag instead and using DomDocument, but it cannot tell me the position of the tag in a string. I cannot use external libraries, i'm just looking for pointers as to how this could be solved. Maybe you've seen an algorithm that does exactly that - i'd like to have a look at it.
Thanks for the help.
P.S. regex solutions will not work since there are nested tags. Recursive regex solutions will not work as well. I'm just looking for a very simple parsing algorighm for this specific case.
What you're talking about here is making a template. Regex for parsing templates is very slow. Instead, your template-reading/processing engine should be doing a string parse. It's not super-easy, but it's also not terribly hard. Still, my advice is use another template library instead of reinventing the wheel.
There's an open-source template engine in PHPBB that you could utilize or learn from. Or, use something like Smarty. If performance is a major deal, have a look at Blitz.
strpos + strrpos (ouch...)
$str = 'sample string with <::Class id="some id" and more">text with possible <::Strong>other<::/Strong> tags inside<::/Class> some more text';
$tag = '<::';
$first = strpos($str, $tag);
$last = strrpos($str, $tag);
$rtn = array();
$cnt = 0;
while ($first<$last)
{
if (!$cnt)
{
$rtn[] = substr($str, 0, $first);
}
++$cnt;
$next = strpos($str, $tag, $first+1);
if ($next)
{
$pos = strpos($str, '>', $first);
$rtn[] = substr($str, $first, $pos-$first+1);
$rtn[] = substr($str, $pos+1, $next-$pos-1);
$first = $next;
}
}
With the $rtn, you can do whatever you want then ... this code is not perfect yet ...
array (
0 => 'sample string with ',
1 => '<::Class id="some id" and more">',
2 => 'text with possible ',
3 => '<::Strong>',
4 => 'other',
5 => '<::/Strong>',
6 => ' tags inside',
7 => '<::/Class> some more text',
)
So basically here's what i came up with. Something like ajreal's solution only not as clean ;] Not even sure if it works perfectly yet, initial testing was successful.
protected function findFirstControl()
{
$pos = strpos($this->mSource, '<::');
if ($pos === false)
return false;
// get the control name
$endOfName = false;
$controlName = '';
$len = strlen($this->mSource);
$i = $pos + 3;
while (!$endOfName && $i < $len)
{
$char = $this->mSource[$i];
if (($char >= 'a' && $char <= 'z') || ($char >= 'A' && $char <= 'Z'))
$controlName .= $char;
else
$endOfName = true;
$i++;
}
if ($controlName == '')
return false;
$posOfEnd = strpos($this->mSource, '<::/' . $controlName, $i);
$posOfStart = strpos($this->mSource, '<::' . $controlName, $i);
if ($posOfEnd === false)
return false;
if ($posOfStart > $pos)
{
while ($posOfStart > $pos && $posOfEnd !== false && $posOfStart < $posOfEnd)
{
$i = $posOfStart + 1;
$n = $posOfEnd + 1;
$posOfStart = strpos($this->mSource, '<::' . $controlName, $i);
$posOfEnd = strpos($this->mSource, '<::/' . $controlName, $n);
}
}
if ($posOfEnd !== false)
{
$ln = $posOfEnd - $pos + strlen($controlName) + 5;
return array($pos, $ln, $controlName, substr($this->mSource, $pos, $ln));
}
else
return false;
}
Not an extendable solution, but it works.
$startPos = strpos($string, '<::Class');
$endPos = strrpos($string, '<::/Class>');
Note my use of strrpos to fix the nesting problem. Also, this will give you the start position of <::/Class>, not the end.
Why don't you just use regular XML and the DOM? Or just an existing template engine like Smarty?

Categories