1

First of all I just want to say that I never understood so well the regular expressions patterns, but I'm progressing :)

I want to create a function for replacing the "^" char and left right matches with pow($1, $2). I manged to get to a point that is acceptable but the string that I receive from an API keeps getting bigger & bigger and now I'm stuck... it's like this:

$str = '(0+1*9^3+3)*(4+5)-(6/7)+(1+2)/(1+1)^((2/3)*3-1+(2/3))';
$str = preg_replace('/([0-9]+|\([0-9\+\-\*\/]+\)|[^\+\-\*\/]\([\S]+\))\^([0-9]+|\([0-9\+\-\*\/]+\)|[^\+\-\*\/]\([\S]+\))/', 'pow($1,$2)', $str);
echo $str;

This works ok to the given string but if i add 1 more "+(1+2)/(1+1)^((2/3)*3-1+(2/3))'" to the end it doesn't work right.

Basically i want preg_replace to find the first "()" from the left & the first "()" from the right of "^" char

Examples of how it should work (I'll only do for the left side of "^" but it can applies as well on the right side)

3+2^3-2 => 3+pow(2, 3)-2
3+(1+1)^3*2 => 3+pow((1+1), 3)*2
3+(1+1+(1+2))^3/2 => 3+pow((1+1+(1+2)), 3)/2
3+((3/3)+(2/2))^2-1 => 3+pow(((3/3)+(2/2)), 2)-1
(3+1)^3-1 => pow((3+1), 3)-1

etc...

Sort for all above is: return as "$1" what is before "^": 1. if the first thing before "^" is int, return the number 2. if the first thing is ")" search for it's pair "(" and return everything inside them (something like '/(/([.*]))\^/')

I'm sorry for my english, I hope you understood... and I hope that someone can help me on this problem :(

Thanks in advance!

Azrael
  • 193
  • 8

1 Answers1

3

The problem here is that you need a parser. Infinitely nested expressions (as in parenthesis) cannot1 be matched by regular expressions alone. Consider this:

(2 ^ (2 ^ (2 ^ (2 ^ (2 ^ (2 ^ (...)))))))

What regular expression will match that? You can approximate it, you can match N levels of that, but you can't do it all.

You should make a parser. If you don't want to, I understand, because it's a lot of work. You may be able to get a regex solution that is good enough for your purposes now. But it won't work forever, because regular expressions are not sufficiently advanced to solve this problem.


  1. Perl (and Perl-compatible regular expressions) can do this, but they shouldn't. Once you start using those features of Perl's regexes it becomes unreadable. Also, they're not (theoretically speaking) regular expressions, but no one really cares about theory. :P
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183