0

I'm using the math.js library and I need to take the exponent of some variables. I have the following strings:

//Ok
pow(y,2)
pow(y,2+2)
pow(y,2-3)
pow(y,2.2)
pow(y,(23)/(2))+23123
pow(y,pow(2,pow(2,4)))-932
pow(y,pow(2,1*pow(2,0.5)))+23

//Erro
pow(y,2)*pow(2,2)
pow(y,3)-pow(2,2)
pow(y,4)+pow(2,2)
pow(y,pow(2,1*pow(2,0.5)))+pow(1,1)

I'm having trouble implementing this search using regex. The pow(a,b) function is composed of two arguments "a" is the base and "b" the exponent.

In the last four strings of the code above, I need to capture only "2", "3", "4" and "pow(2,1*pow(2,0.5))". I don't want to take the part after "*", "+" and "-".

Since it is possible to chain the pow() function and both "a" and "b" can have arithmetic operators and functions like pow() and sqrt(), this turned out to be very complex. Is there any way to resolve this using regex?

The closest I got is in this regex: https://regex101.com/r/hB1cg4/4

  • 2
    Matching balanced expressions is hard in regular expressions. – Barmar Mar 20 '20 at 05:41
  • 1
    [You could try `\(y,([^)]+)\)`](https://regex101.com/r/gVB9j7/1) or [this](https://regex101.com/r/6zCKCQ/1) – shrys Mar 20 '20 at 05:46
  • 1
    Unfortunately Javascript does not support recursive regex natively. You can use different work-arounds to make the recursive pattern, but better approach is just to use a mix of regex and normal code. Move through your string incrementing a parenthesis counter when encountering '(' and decrementing it when encountering ')'. When the counter is zero - you found the closing parenthesis for the initial opening parenthesis. – Alex Mar 20 '20 at 06:07
  • Thanks for the tip Alex – Pedro Castro Mar 20 '20 at 18:50

2 Answers2

1

As stated in the comments, doing balanced match is hard in regex, though the .NET regex flavor supports this feature. Please see this answer: https://stackoverflow.com/a/35271017/8031896

Nevertheless, there is a work-around that uses the common regex flavors. However, please note that you may need to modifiy it according to the number of parentheses recursion layer in your mathematic notation.

((?<=^pow)\(([^()]*|\(([^()]*|\([^()]*\))*\))*\))

demo: https://regex101.com/r/hB1cg4/6

For more detailed explanation, please see this answer: https://stackoverflow.com/a/18703444/8031896

zhugen
  • 136
  • 7
1

The following regex matches all of the "Euro" strings, and one variant, but unfortunately fails to match two of the "OK" strings. Perhaps some tweaking is possible. The regex contains a single capture group that captures the information of interest.

^pow\([^,]+,(\d[^()]*|pow\(\d+,\d+(?:\)|[^()]*\([^()]*\)\)))\).*

Javascript demo

To match the "Euro" strings I assumed that pow(2,1*pow(2,0.5)) in pow(y,pow(2,1*pow(2,0.5)))+23 represented the maximum number of nested "pow"'s.

The regex performs the following operations.

^               # match beginning of line
pow\(           # match 'pow('
[^,]+           # match 1+ chars other than ','
,               # match ','
(               # begin capture group 1
  \d[^()]*      # match a digit, 0+ chars other than '(' and ')' 
  |             # or
  pow\(\d+,\d+  # match 'pow(', 1+ digits, ',' 1+ digits
  (?:           # begin non-cap grp
    \)          # match ')'
    |           # or
    [^()]*      # match 0+ chars other than '(' and ')' 
    \(          # match '('
    [^()]*      # match 0+ chars other than '(' and ')' 
    \)\)        # match '))'
  )             # end non-cap grp
)               # end cap grp 1
\)              # match ')'
Cary Swoveland
  • 94,081
  • 5
  • 54
  • 87