0

I needed a regular expression for a mathematical expression, which should satisfy the following conditions explained in this SO Question which was asked by me.

It worked fine with this expression

But now I need to add the support for opening and closing parenthesis along with previous conditions. So that my regular expression should validate the expressions of these patterns

eg. *6+(7-9) or /6.25*(7-9.2) or +6 or *6/(7.5-9)

I tried to make modifications to the existing regular expression but was not successful in achieving. It also accepts these patterns *6+(7-9 and *6+7-9) which are not valid, as single parenthesis can be present in a mathematical expression.

Here's the link RegExr . Please help.

Community
  • 1
  • 1
Bibhu
  • 4,053
  • 4
  • 33
  • 63
  • 1
    No, you can't use regex for this. Write a small parser. – leppie Jul 04 '12 at 06:29
  • Which regex engine are you using? This can only be done with a regex engine that supports recursion like .NET or Perl, and even then, it's going to be a very hairy regex. – Tim Pietzcker Jul 04 '12 at 06:30
  • 2
    A real parser will be a *lot* more maintainable. – Asherah Jul 04 '12 at 06:44
  • @Tim Pietzcke - I am using the regular expression to validate the text for a textbox, in my asp.net application. What you suggest in such a case. – Bibhu Jul 04 '12 at 07:02

2 Answers2

5

@Bibhu, since mathematical expressions can be nested arbitrarily, you need an actual parser to validate them. A regular expression won't work. Regular expressions are not powerful enough to deal with arbitrarily deep recursive nesting.

If you limit the nesting to a maximum level, you could write a (very big and ugly) regexp which could validate the expressions. But fundamentally, regexps are the wrong tool for the job.

If you have a parser generator which you already know how to use, that would be the easiest way to build a parser for mathematical expressions. If you don't, writing a simple top-down recursive-descent parser by hand is still quite easy.

Alex D
  • 29,755
  • 7
  • 80
  • 126
  • This is not entirely true. Hardly any current "regex" engine is restricted to actually "regular" expressions. Many do support recursion. Apart from this fact, this is more of a comment than an answer. – Tim Pietzcker Jul 04 '12 at 06:31
  • @TimPietzcker, thanks for pointing that out. I am actually aware that some regex engines support recursion, and have posted answers on SO before which mention that fact. In this case, I think a recursive-descent parser is the best solution, and don't want to confuse the issue. If you want to post an answer demonstrating how to solve the problem using "non-regular regular expressions", please do so. You'll need to find out what language the OP is using to get the correct syntax. – Alex D Jul 04 '12 at 06:39
  • That's why I wrote my comment to Bibhu's question. RegExr, at least, doesn't seem to support recursive regexes... – Tim Pietzcker Jul 04 '12 at 06:41
  • @Alex D - I am using the regular expression to validate the text for a textbox, in my asp.net application. What you suggest in such a case. – Bibhu Jul 04 '12 at 07:04
0

I'm wondering if you're offering a bounty.

Simple recursion in regex is a gosub with a pass/fail return that happens to be stackable.

Below is a Perl routine that passes Perl's own parsing algol for the simple operators and simple syntax rules you specified. It's done in a single regex because your needs are extremely simple.

It looks fancy but resolves to the simple balanced text of '()'. It looks like Dot Net
can do this. It should be real easy to just do the substitution's (ie; (?&var) ), do
the balanced grouping Dot Net requires... instant validation.

I'm posting this because, nesting is not the problem. The problem is that as simple as
parsing seems, the devil is in the details.

^
(?:
     ^ (?&sign)? (?&number)
  |
     (?&operator) 
     (?<! ^ (?:\/|\*) )
     (?<! ^ [*]{2} )
     (?&sign)? (?&number)
  |
     (?: (?&operator)
         (?<! ^ (?:\/|\*) )
         (?<! ^ [*]{2} )
         (?<! [(] (?:\/|\*) )
         (?<! [(] [*]{2} )
         (?&sign)?
       |
         (?<= [(] )
       |
         ^ (?&sign)?
     )

     (?<term>
        \(
           (?:
                (?>  (?&sign)?
                     (?&number)
                     (?: (?&operator) (?&sign)? (?&number) )*
                )
             |
                (?>
                    (?: (?<= [(] ) | (?&operator) )
                    (?<! [(] (?:\/|\*) )
                    (?<! [(] [*]{2} )
                    (?&sign)?
                    (?&term)
                )
           )*
        \)
        (?! [(] )
        (?> (?&operator) (?&sign)? (?&number) )*
     )
)*
$

(?(DEFINE)
  (?<number>    \d+(?:\.\d+)?   )
  (?<sign>      [+-]            )
  (?<operator>
        (?:  [*]{2}
          |  [\/*]
          |  (?<pm>[-+]) (?! \k<pm>) )
         )
  )

Output

passed  ''
passed  '(6**-2**3)'
passed  '6-+2'
passed  '-(-(8*((2)/3)))'
passed  '-((8*((2)/3)))'
passed  '-((8*((2**4)/3)))'
passed  '-((8*((2**4)/3)))**((-1)*(8*((2**4/99)/3)))'
passed  '-((8*((2**4)/3)))**((-1)*(8*((2**-4/99)/3)))'
passed  '-((8*((2**4)/3)))**-((-1)*(8*((2**-4/99)/3)))'
passed  '((8*((2)/3)))'
passed  '((8*((2)/3)))'
passed  '+((8*((-2)/-3)))'
passed  '8-6*2'
passed  '-8-6*2'
passed  '((8*((2-(8*(8+6)/2))/3))-7*2/234)+8/2*1'
passed  '-(8*(8+6)/2)'
passed  '(9*9/9)'
passed  '(9*(9)/9*(9*(9)/9)*1)'
passed  '(9*(9)/9*(9*(9)/9))*(9*(9)/9*(9*(9)/9))'

failed  '(6--2)'
failed  '-(/(8*((2)/3)))'
failed  '-((8*((2(6))/3)))'
failed  '+((8*((+2)/--3)))'
failed  '+((8*((+2)/--3+)))'
failed  '+((8*((*2)/--3)))'
failed  '+((8*((*2)/-3)))'
failed  '-((8*((-2)/+-3)))'
failed  '+8/2(1)'
failed  '-(8)*(8/('
failed  '-(8)*(8/()'
failed  '*(9*9/9)'
failed  '*(9*(9)/9*(9*(9)/9))*(9*(9)/9*(9*(9)/9))'
failed  '/(9*(9)/9*(9*(9)/9))*(9*(9)/9*(9*(9)/9))'