2

Tried to search for an already answered question but ... couldn't find anything. I'm trying to make a regex that will match ipv4 or ipv4:port

$regex_ipv4 = '((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?![\\d])';
$regex_integer = '(\\d+)';

$x = "123.123.123.123";
$x2 = $x . ":12345";

preg_match("/^(?<ipv4>".$regex_ipv4.")(:)(?<port>".$regex_integer.")$/is", $x, $matches1);
preg_match("/^(?<ipv4>".$regex_ipv4.")(:)(?<port>".$regex_integer.")$/is", $x2, $matches2);

print_r($matches1);
print_r($matches2);

returns:

Array
(
)
Array
(
    [0] => 123.123.123.123:12345
    [ipv4] => 123.123.123.123
    [1] => 123.123.123.123
    [2] => 123.123.123.123
    [3] => :
    [port] => 12345
    [4] => 12345
    [5] => 12345
)

How can I make unconditional match of (:)(?<port>".$regex_integer.") ?

Thank you!

5
  • 1
    What do you mean by unconditional match of...? Commented Feb 28, 2016 at 14:45
  • ((:)(?<port>".$regex_integer."))? ? Commented Feb 28, 2016 at 14:48
  • It seems the code is working, the named groups capture what you need. Commented Feb 28, 2016 at 14:50
  • I want this regex: "^(?<ipv4>".$regex_ipv4.")(:)(?<port>".$regex_integer.")$" to strictly match "ipv4" OR "ipv4:port" in one line Commented Feb 28, 2016 at 15:22
  • 1
    Try preg_match("/^(?<ipv4>".$regex_ipv4.")(?::(?<port>".$regex_integer."))?$/", $x, $matches); Commented Feb 28, 2016 at 15:47

1 Answer 1

1

You must be searching for an optional group at the end of the pattern. It can look like:

^(?<ipv4>((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?!\d))(?::(?<port>\d+))?$

See the regex demo

In your code, use

preg_match("/^(?<ipv4>".$regex_ipv4.")(?::(?<port>".$regex_integer."))?$/", $x, $matches);

Note that the capturing group around a : is redundant. (?: starts the non-capturing group, )? at the end of the regex closes the group and ? quantifier makes the regex engine match this group 1 or 0 times.

And to clean up the regex patterns, I'd suggest to remove redundant character class with just one symbol and redundant capture groups:

$regex_ipv4 = "((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?!\\d)";
$regex_integer = "\\d+";

And here is a complete PHP demo:

$regex_ipv4 = "((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(?!\\d)";
$regex_integer = "\\d+";

$x = "123.123.123.123";
$x2 = $x . ":12345";

preg_match("/^(?<ipv4>".$regex_ipv4.")(?::(?<port>".$regex_integer."))?$/", $x, $matches);
preg_match("/^(?<ipv4>".$regex_ipv4.")(?::(?<port>".$regex_integer."))?$/", $x2, $matches2);

print_r($matches);
print_r($matches2);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.