RegEx Challenge: capture all numbers in a specific row

Suppose we have this text:

... settingsA=9, 4.2 settingsB=3, 1.5, 9, 2, 4, 6 settingsC=8, 3, 2.5, 1 ... 

The question is, how can I capture all the numbers that are on a particular line using one step?

One step means:

  • single regex pattern.
  • single operation (no loops or partitions, etc.)
  • all matches are recorded in one array.

Let's say I want to write down all the numbers that are on the line that starts with settingsB= . The end result should look like this:

 3 1.5 9 2 4 6 

My unsuccessful attempts:

 <?php $subject = "settingsA=9, 4.2 settingsB=3, 1.5, 9, 2, 4, 6 settingsC=8, 3, 2.5, 1"; $pattern = '([\d\.]+)(, )?' // FAILED! $pattern = '(?:settingsB=)(?:([\d\.]+)(?:, )?)' // FAILED! $pattern = '(?:settingsB=)(?:([\d\.]+)(?:, )?)+' // FAILED! $pattern = '(?<=^settingsB=|, )([\d+\.]+)' // FAILED! preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER); if ($matches) { print_r($matches); } ?> 

UPDATE 1: The @Saleem example uses, unfortunately, several steps instead of a single step. I am not saying that his example is bad (it really works), but I want to know if there is another way to do this and how. Any ideas?

UPDATE 2: The @bobble bubble provided the perfect solution for this task.

+6
source share
2 answers

You can use the \G anchor to match matches to the end of the previous match. This pattern, which also uses \K to reset , before the desired part will work with the flavor of the regular expression PCRE.

 (?:settingsB *=|\G(?!^) *,) *\K[\d.]+ 
  • (?: opens a group not for capture for alternation
  • match settingsB followed by * any number of spaces followed by the letter =
  • |\G(?!^) Or continue when the previous match ended, but did not start
  • *, and match a comma preceded by extra space
  • ) end of rotation (group without capture)
  • *\K reset after extra space
  • [\d.]+ correspond to one or more digits and periods.

If the sequence contains tabs or newlines, use \s instead of the space character.

See demo in regex101 or PHP demo at eval.in

or this more compatible pattern using a capture group instead of \K , which should work in any regex expression that supports \G binding (Java, .NET, Ruby ...)

+4
source

Here is a python solution, but will post PHP rx later. However, python and php regular expressions are very similar.

 (?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+ 

Python:

 import re subject = """ ... settingsA=9, 4.2 settingsB=3, 1.5, 9, 2, 4, 6 settingsC=8, 3, 2.5, 1 ... """ rx = re.compile(r"(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+", re.IGNORECASE) result = rx.search(subject) if result: numString = result.group() for n in [f.strip() for f in numString.split(',')]: print(n) 

Php

 $subject = "settingsA=9, 4.2 settingsB=3, 1.5, 9, 2, 4, 6 settingsC=8, 3, 2.5, 1"; $pattern = '/(?<=settingsB=)(\d+(?:\.\d+)?(?:, )?)+/i'; preg_match($pattern, $subject, $matches); if ($matches) { $num = explode(",", $matches[0]); for ($i = 0; $i < count($num); $i++) { print(trim($num[$i]) . "\n"); } } 

Output:

 3 1.5 9 2 4 6 
+1
source

All Articles