Regex capture two digits Only if there are no other numbers in the string

Viewed 143

I want to find and capture two digits Only if there are no other numbers in the string, My inputs:

foo 12 ✅
foo 12 bar ✅
12 baz ✅
9 foo 12 ❌
foo 12 baz 2 ❌
12 2 ❌

I tried this pattern

preg_match('`(?<=\d)\b\d\d\b(?=\d)`', $input);

But not working

https://regex101.com/r/Gsvguc/1

2 Answers

You need to check the whole string to contain there aren't any other digits, so start at the beginning. Match non-digits, then use \K to reset the match (this is needed for the result to contain only the two digits you want), match the 2 digits, and lookahead for no more digits until the end of the string:

^\D*\K\d{2}(?=\D*$)

https://regex101.com/r/Gsvguc/2

Another option is to fail a string with two digits separated with non-digits and then match two digits:

.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b

See proof:

enter image description here

Explanation

--------------------------------------------------------------------------------
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  \d                       digits (0-9)
--------------------------------------------------------------------------------
  \D+                      non-digits (all but 0-9) (1 or more times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  \d                       digits (0-9)
--------------------------------------------------------------------------------
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  (*SKIP)                    backtracking control verb that makes the regex engine
                             "skip" forward to this position on failure and tries 
                             to match again
--------------------------------------------------------------------------------
  (*F)                       fail the current match, proceed to search for a new one
--------------------------------------------------------------------------------
 |                        OR
--------------------------------------------------------------------------------
  \b                       the boundary between a word char (\w) and
                           something that is not a word char
--------------------------------------------------------------------------------
  \d{2}                    digits (0-9) (2 times)
--------------------------------------------------------------------------------
  \b                       the boundary between a word char (\w) and
                           something that is not a word char

PHP example:

if (preg_match('~.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b~', 'foo 12', $match)) { echo "foo 12 >>> $match[0]\n"; }
if (preg_match('~.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b~', '12 baz', $match)) { echo "12 baz >>> $match[0]\n"; }
if (preg_match('~.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b~', '9 foo 12', $match)) { echo "9 foo 12 >>> $match[0]\n"; }
if (preg_match('~.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b~', 'foo 12 baz 2', $match)) { echo "foo 12 baz 2 >>> $match[0]\n"; }
if (preg_match('~.*\d\D+\d.*(*SKIP)(*F)|\b\d{2}\b~', '12 2', $match)) { echo "12 2 >>> $match[0]\n"; }

Result:

foo 12 >>> 12
12 baz >>> 12
Related