Search code examples
phpregexpreg-matchpreg-match-all

preg_match_all - Match two options


preg_match confuses me so I apologise if this is a simple question or been asked before but I can't make sense of answer to know if its what I need.

I have a string that follows this format: Test 1#1.00 Test 2#2.00 Test 3#3.00

I then use this pattern to seperate the values /(?P<first>([^**]*?))#(?P<second>\d{0,7}(?:\.\d{1,2}))/

So end up with

Array ( [0] => Test 1 [1] => Test 2 [2] => Test 3 )

Array ( [0] => 1.00 [1] => 2.00 [2] => 3.00 )

Where I'm struggling is changing the pattern to find a decimal like it currently does or the word/letters FOC or TBC

So my string will be for example: Test 1#1.00 Test 2#FOC Test 3#3.00

and my arrays will be:

Array ( [0] => Test 1 [1] => Test 2 [2] => Test 3 )

Array ( [0] => 1.00 [1] => FOC [2] => 3.00 )

Currently, my pattern won't work with FOC and will just return the first in each array.

Any help greatly appreciated.


Solution

  • My suggestion is to add a \w+ alternative before the regex engine tries to match a number:

    (?P<first>[^#]*)#(?P<second>\d{0,7}\.\d{1,2}|\w+)
    

    Or, to start matching keys with the first non-whitespace char (demo):

    (?P<first>[^#\s][^#]*)#(?P<second>\d{0,7}\.\d{1,2}|\w+)
              ^^^^^^
    

    See the regex demo.

    Details

    • (?P<first>[^#]*) - Group "first" matching 0+ chars other than # (it is a negated character class here due to ^ being the first char after [)
    • # - a # symbol
    • (?P<second>\d{0,7}\.\d{1,2}|\w+) - Group "second" that matches
      • \d{0,7}\.\d{1,2} - 0 to 7 digits followed with . and then 1 or 2 digits
      • | - or
      • \w+ - 1+ word chars (letters, digits or _)

    See the PHP demo:

    $re = '/(?P<first>[^#]*)#(?P<second>(?:\d{0,7}\.\d{1,2}|\w+))/';
    $str = 'Test 1#1.00 Test 2#2.00 Test 3#3.00
    Test 1#1.00 Test 2#FOC Test 3#3.00';
    preg_match_all($re, $str, $matches);
    print_r($matches["first"]);
    echo "\n";
    print_r($matches["second"]);