2

I have a preg_match() to try and capture math problems, but it's only working partially. While it capture the 'plus' and the last 'one', it doesn't capture the first 'one' for some reason. What am I doing wrong?

$string = "one plus one";

if (preg_match("~([0-9]|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety|hundred|thousand|million|\-| )+(\+|\-|\*|\/|plus|add|minus|subtract|time|multiply|divide)([0-9]|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety|hundred|thousand|million|\-| )+~", $string, $match)) {    
    print_r($match);
}

Result:

Array ( [0] => one plus one [1] => [2] => plus [3] => one )

Expected Result:

Array ( [0] => one plus one [1] => one [2] => plus [3] => one )
Rizier123
  • 58,877
  • 16
  • 101
  • 156
frosty
  • 2,559
  • 8
  • 37
  • 73

1 Answers1

0

You can put your current capturing group with all alternatives into another one, so you capture everything and don't overwrite it every time when you encounter something like twenty nine.

~
[+-]? #number sign e.g. +5 or -5
((?:\d|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety|hundred|thousand|million|-|\s)+) #numbers
([+*/-]|plus|add|minus|subtract|time|multiply|divide) #operation
\s*[+-]? #number sign e.g. +5 or -5
((?:\d|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety|hundred|thousand|million|-|\s)+) #numbers
~x

(Modifier x, just used for explanation and formatting)

Rizier123
  • 58,877
  • 16
  • 101
  • 156
  • But we can't take the space out. What if someone types "Three hundred forty six"? There's like 3 spaces in between those numbers. – frosty Apr 04 '16 at 19:57
  • Also, I absolutely need the spaces in between, because after I match them, I need to translate the text to actual numbers. – frosty Apr 04 '16 at 19:59
  • @frosty Ah now I see. Updated my answer. – Rizier123 Apr 04 '16 at 20:01
  • Tried it. It didn't print_r out anything. – frosty Apr 04 '16 at 20:03
  • Can you remove the explantions, and also this won't match something like "one plus one plus one" – frosty Apr 04 '16 at 20:13
  • @frosty Well that would be getting a bit difficult if you want to catch repeated capturing groups, means stuff like `a + b + c`. I would recommend you to use a function and recursively parse `a operation b` one at a time. Which will make things a lot simpler. – Rizier123 Apr 04 '16 at 20:19
  • I don't think I'm quite at that level yet. Just trying to do this using regex. – frosty Apr 04 '16 at 20:21
  • maybe we can use preg_match_all? – frosty Apr 04 '16 at 20:22
  • @frosty *"I don't think I'm quite at that level yet."*, That is why I would recommend you to parse one operation at the time. Especially when you want to take into account that `*` comes before `+` and so on. See: http://stackoverflow.com/a/27077376/3933332 for example. You could just extend this with your pattern if you want to parse complex'er math expressions. – Rizier123 Apr 04 '16 at 20:28
  • @frosty If you say you want to parse "complex" math expressions, I would recommend you to look at the answer above ^^ and just first replace all numbers written out back to real numbers, e.g. `one` -> `1`. – Rizier123 Apr 04 '16 at 20:52