2

I'm trying to write a regex to use in an if statement in PHP to check is a string contains at least 1 +, -, *, or / and at least 2 numbers. There can be any number of spaces in between them.

What is the best way to do this?

I tried writing a regex, below, but that doesn't seem to match my test cases.

The regex i'm using is: m/[0-9]{2,}[=-*/]+/

Here some test cases that would pass:

  1. 2 +2
  2. 5*3
  3. 6 - 8

My ultimate goal is to build a calculator in PHP and right now I am trying to determine what input is valid mathematical input / a valid mathematical expression and what is not.

JayGatz
  • 271
  • 1
  • 8
  • 18

2 Answers2

1

This will match your tests.

/^
[0-9]+    # first number
\s*       # any whitespace
[+*\/-] # operand
\s*       # any whitespace
[0-9]+    # second number
$/x
Evert
  • 93,428
  • 18
  • 118
  • 189
  • Note that you don't need to escape `+*/` in a character class, but you do need to escape a `-` if it's in the middle of a character class otherwise it will specify a range ! For example `8 , 5` will get matched since `,` is in the range of `*` and `/` according to the [ascii table](http://www.asciitable.com/). [Online demo](http://regex101.com/r/jI5oR0). So if you use `[+*/-]` you won't need to escape `-`, but wait you do need to escape the slash if it's used as [delimiter](http://regex101.com/r/xV9mG9). – HamZa Jun 02 '13 at 21:39
  • @HamZa: Warning: preg_match(): Unknown modifier '-' ;) gonna escape that dash – Evert Jun 02 '13 at 21:42
  • 1
    @HamZa: sorry that was due to the `\` before `/` missing – Evert Jun 02 '13 at 21:43
1

Your regex won't ever match single digit numbers because you're using {2,} which means match a character 2 or more times.
So let's take a look at this regex here:
#(\d+)\s*([+/*-])\s*(\d+)#

  • # : delimiter
  • (\d+) : Match a digit one or more times and then group it.
  • \s* : Match a space zero or more times
  • ([+/*-]) : Match either + or - or * or / one time and group it
  • \s* : Match a space zero or more times
  • (\d+) : Match a digit one or more times and then group it.
  • # : delimiter

Let's use some PHP-Fu here and a function I used here:

$input = '2 +2
5*3
6 - 8';

$output = preg_replace_callback('#(\d+)\s*([+/*-])\s*(\d+)#', function($m){
    return $m[1].' '.$m[2].' '.$m[3].' = '. mathOp($m[2], (int)$m[1], (int)$m[3]);
}, $input); // You need PHP 5.3+. Anonymous function is being used here !
echo $output;

function mathOp($operator, $n1, $n2){
    if(!is_numeric($n1) || !is_numeric($n2)){
        return 'Error: You must use numbers';
    }
    switch($operator){
        case '+':
            return($n1 + $n2);
        case '-':
            return($n1 - $n2);
        case '*':
            return($n1 * $n2);
        case '/':
            if($n2 == 0){
                return 'Error: Division by zero';
            }else{
                return($n1 / $n2);
            }
        default:
            return 'Unknown Operator detected';
    }
}

Output:

2 + 2 = 4
5 * 3 = 15
6 - 8 = -2

Advice:
This will get rather complicated with negative numbers, parenthesis, log and cos/sin functions so you're better off using a parser.

Community
  • 1
  • 1
HamZa
  • 14,671
  • 11
  • 54
  • 75
  • Thank you very much for the explanation and help! This helped a lot. Where can I get a or find a mathematical parser for PHP ? – JayGatz Jun 03 '13 at 00:00
  • @JayGatz Sorry I don't know any that I've tried, you maybe should search for one and try it out. Also please be prudent of those solutions that uses eval(), test them as they may have some security problems. – HamZa Jun 03 '13 at 08:07
  • @JayGatz Ok I asked [Dave](http://stackoverflow.com/users/889949) and here's what [he suggested](http://chat.stackoverflow.com/transcript/message/9773856#9773856). – HamZa Jun 03 '13 at 08:38