Regex: how to capture a group starting with a matched set of characters

Viewed 52

Here is a string of characters that I would like to split into an array:

35g walnut halves A handful of thyme leaves 200g portobello mushrooms 200g white mushrooms 200g chifferini pasta 100g Petit Brebis sheep's cheese 40g honey

I would like to use preg_split to extract the individual ingredients from the string. An individual ingredients starts with:

  • a quantity defined by digits plus the character g
  • a sequence a characters such as A handful

So far, I have this regex pattern ([0-9]+g|A handful) which correctly finds the breaks in the string, but doesn't include the entire ingredient description. I need the capturing group to include the rest of the characters until the next match.

In order to get the array return, I use this PHP:

preg_split("/([0-9]+g|A handful)/", $ingredients_str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY)

The desired output is:

[
  0 => 35g walnut halves
  1 => A handful of thyme leaves
  2 => 200g portobello mushrooms
  etc..
]

See regex 101

1 Answers

You can use preg_match_all to extract all the descriptions:

preg_match_all('~(?:\d+g|A handful).*?(?=\s*(?:\d+g|A handful|$))~s', $str, $matches)

See the regex demo.

Details

  • (?:\d+g|A handful) - 1+ digits followed with g or A handful
  • .*? - any zero or more chars, as few as possible
  • (?=\s*(?:\d+g|A handful|$)) - up to a location in string that is immediately followed with 0+ whitespaces followed with either 1+ digits and g, or A handful or end of string.

See the PHP demo:

$re = '/(?:[0-9]+g|A handful).*?(?=\s*(?:[0-9]+g|A handful|$))/s';
$str = '35g walnut halves A handful of thyme leaves 200g portobello mushrooms 200g white mushrooms 200g chifferini pasta 100g Petit Brebis sheep\'s cheese 40g honey';
if (preg_match_all($re, $str, $matches)) {
   print_r($matches[0]);
}

Output:

Array
(
    [0] => 35g walnut halves
    [1] => A handful of thyme leaves
    [2] => 200g portobello mushrooms
    [3] => 200g white mushrooms
    [4] => 200g chifferini pasta
    [5] => 100g Petit Brebis sheep's cheese
    [6] => 40g honey
)

A preg_split solution may look like

$re = '/(?!^)\b(?=[0-9]+g|A handful)/';
$str = '35g walnut halves A handful of thyme leaves 200g portobello mushrooms 200g white mushrooms 200g chifferini pasta 100g Petit Brebis sheep\'s cheese 40g honey';
print_r(preg_split($re, $str));

See the demo online. Here,

  • (?!^) - matches a location that is not at the start of string
  • \b - word boundary
  • (?=[0-9]+g|A handful) - a location that is immediately followed with 1+ digits and then g or A handful substring.
Related