'How to check that fifth and sixth characters are a specific two-digit number?

I would like to validate phone numbers. The only valid phone numbers start like this: +36 20 | +36 30 | +36 31 | +36 70

My code looks like this, but now you can enter +36 21 or +36 71 which I would like to avoid. How can I check for a two digit number? Like 70 or 30.

$phone = '+36 70 123 4567';

if ( preg_match( '|^\+36 [237][01] [1-9][0-9]{2} [0-9]{2}[0-9]{2}$|', $phone ) ) { 
    echo 'phone number is good';
}


Solution 1:[1]

You may use non-capturing groups to specify the values you need to allow:

^\+36 (?:[237]0|31) [1-9][0-9]{2} [0-9]{4}$

See the regex demo

The [237][01] (two consecutive character classes) matches 2 or 3 or 7 followed with 0 or 1, while (?:[237]0|31) matches either 2, 3, 7 and then 0, or 31 char sequence.

The whole pattern matches:

  • ^ - start of stirng
  • +36 - +36 and a space
  • (?:[237]0|31) - see description above
  • - space
  • [1-9] - a character class matching a single digit rom 1 to 9 (excludes 0)
  • [0-9]{2} - any 2 ASCII digits (from 0 to 9)
  • - space
  • [0-9]{4} - 4 digits
  • $ - end of string.

Note that instead of literal spaces, you may use \s that matches any whitespace, and to match 1 or 0 occurrences (if the whitespace is optional) you may add ? (or * to match 0+ occurrences) after \s - \s? / \s*.

Solution 2:[2]

$re = '/\+36\s(20|30|31|70)\s.*/';
$str = '+36 20 4145654';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

var_dump($matches);

Here I used \s to match all whitespace characters. Of course you can also use space character only like this:

$re = '/\+36 (20|30|31|70) .*/';

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wiktor Stribiżew
Solution 2 user1915746