0

I need to split a given user string into an array based around mathematical operators. The symbols I need the string splitting around are:

+
-
/
*
()

However I would like to expand on the regex to include other operators I will be adding into my program. The regex I have so far is this:

"((\(|\d+.+|-|\*|\/\d+\|))"

which when ran through regex101.com matches a given input string of: (30*30)/(9+8) with '30*30)/(9+8)

I would like the output to be similar to this:

[0] = 
[1] = (
[2] = 30
[3] = *
[4] = 30
[5] = )

or: 
 [0] = 
 [1] = 4
 [2] = *
 [3] = 4

depending on whether brackets are present in the user string or not.

I forgot to include current results of the current regex string: using http://www.phpliveregex.com/ to test preg-split with an input string of:

(30*30)+(9*8)
the result:
array(3
0 =>    
1 =>    
2 =>    
)
Nekasus
  • 15
  • 3
  • What doesn't work in your code? – Toto Aug 24 '17 at 10:45
  • It's an example for what I would like the output to look like should the user string not contain brackets. As for what doesnt work in my code, the regex string im using returns nothing but an empty array – Nekasus Aug 24 '17 at 10:56
  • What is expected result for `(30*-30)/(-9+8)`? – Toto Aug 24 '17 at 10:59
  • if you use "()|" on http://www.phpliveregex.com/ I believe it gives the result you want... – Kathara Aug 24 '17 at 11:01
  • [0] = [1] = ( [2] = 30 [3] = * [4] = -30 [5] = ) [6] = / [7] = ( [8] = -9 [9] = + [10] = 8 [11] = ) – Nekasus Aug 24 '17 at 11:02
  • Close, I do wish for non-single digits to be stored in an individual index rather than separated into single digits with their own indexes. – Nekasus Aug 24 '17 at 11:03
  • @Nekasus, I'm not sure if you've found a solution yet but with preg_split i found the following regex: "(?=((?<=\(|\/|\*|\)|\+)|(?>\)|\(|\*|\/|\+)))" just in case you need it ;) – Kathara Aug 24 '17 at 11:36
  • Possible duplicate of [Regex to split string into array of numbers and characters using PHP](https://stackoverflow.com/questions/45607486/regex-to-split-string-into-array-of-numbers-and-characters-using-php) – mickmackusa Aug 31 '17 at 15:31

2 Answers2

0

Is this the pattern you are looking for?

preg_match_all("/(\(|-\d+|\d+|-|\+|\/|\*|\))/", $input, $output);

https://regex101.com/r/acKW27/3

Preg_match_all: http://www.phpliveregex.com/p/l7L

I forgot / in the regex. Links updated also.

Andreas
  • 23,610
  • 6
  • 30
  • 62
  • The output from that preg_split just returns a "/" at index [5]. I want the input string to be split around the operators while still including them in the array – Nekasus Aug 24 '17 at 11:00
  • Don't use split. Use preg_match_all. – Andreas Aug 24 '17 at 11:02
  • How come? I've seen the same thing said before but there was no explanation on why preg_match is more suitable than preg_split – Nekasus Aug 24 '17 at 11:04
  • Because preg split will split and remove your delimiter. (Unless you add the keep delimiter, but usually it's harder to get right). Preg match does the same as preg split in this case – Andreas Aug 24 '17 at 11:11
  • ah ok, thanks for explaining and for providing a solution :) – Nekasus Aug 24 '17 at 11:13
  • Doesn't work with negative numbers: `(30*-30)/(-9+8)` see comment https://stackoverflow.com/questions/45859533/preg-split-regex-need-to-split-user-input-around-mathematical-operators#comment78677552_45859533 – Toto Aug 25 '17 at 12:43
  • Sorry but there is another case that doesn't work `(30-4)` – Toto Aug 25 '17 at 14:55
0

preg_split() retains the delimiters by using the PREG_SPLIT_DELIM_CAPTURE flag. Include the additional flag PREG_SPLIT_NO_EMPTY to eliminate any empty elements. Here is an improved answer that will handle your sample input data, as well as floats and negative numbers.

Code: (Demo)

$expression = '-1*(2/(3+4)--10*-110.5/0.009+-.1)';

var_export(
    preg_split(
        '~(-?\d*(?:\.\d+)?|[()*/+-])~',
        $expression,
        0,
        PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE
    )
);

Output:

array (
  0 => '-1',
  1 => '*',
  2 => '(',
  3 => '2',
  4 => '/',
  5 => '(',
  6 => '3',
  7 => '+',
  8 => '4',
  9 => ')',
  10 => '-',
  11 => '-10',
  12 => '*',
  13 => '-110.5',
  14 => '/',
  15 => '0.009',
  16 => '+',
  17 => '-.1',
  18 => ')',
)

*Note, my above pattern makes digits before the decimal optional. If you know that your floats will always have a number before the dot, then you can use this pattern:

~(-?\d+(?:\.\d+)?|[()*/+-])~

The advantages are: no empty matches, no need for PREG_SPLIT_NO_EMPTY, and improved pattern efficiency.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136