PHP: preg_match for "some multiple words string" + [\s* + "<some.email@address>"]

Viewed 192

Need for parse strings which are appears in the following possible forms:

Some User Name 
Some User Name <user.mail@address>

So username (multiple words) always exists but email is optional and contained in angle brackets.

I need to catch from those:

  1. Username, one string with multiple words separated by \s or \h
  2. Following next email address (if exists) without angle brackets. If no email address specified then resulting submask array should be empty (but always exists in result).

I tried some variations of

preg_match('/^(.*?)\s*(?:\<(.*)\>)?$/s', $in, $out)

but this not work.

Thanks anybody help me.

1 Answers

To get all the separate words separated by \h and an optional email address, you could make use of the \G anchor to get iterative matches, asserting the position at the end of the previous match.

(?|^(\w+)|\G(?!^)\h+(\w+))(?:\h+<([^<>\r\n]+)>$)?

Explanation

  • (?| Branch reset group (To keep the words in $matches[1])
    • ^(\w+) Start of string, match 1+ word chars in group 1
    • | Or
    • \G(?!^) Assert the position at the end of the previous match, not at the start
    • \h+(\w+) Match 1+ horizontal whitespace chars in group 1
  • ) Close branch reset group
  • (?: Non capture group
    • \h+ Match 1+ horizontal whitespace chars
    • <([^<>\r\n]+)>$ Capture the email address between <> in group 2 at the end of string
  • )? Close non capture group and make it optional

Regex demo | Php demo


Use preg_match_all to get all the values.

The default flag is PREG_PATTERN_ORDER which:

Orders results so that $matches[0] is an array of full pattern matches, $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.

The words are in $matches[1] and the email is in $matches2

If the email is not present, the array will be there, but empty.

You could use array_filter to remove the empty entries from the email array.

Example code

$pattern = "~(?|^(\w+)|\G(?!^)\h+(\w+))(?:\h+<([^<>\r\n]+)>$)?~";
$strings = [
    "Some User Name ",
    "Some User Name <user.mail@address>"
];

foreach ($strings as $str) {
    preg_match_all($pattern, $str, $matches);
    print_r($matches[1]);
    print_r(array_filter($matches[2]));
}

Output

Array
(
    [0] => Some
    [1] => User
    [2] => Name
)
Array
(
)
Array
(
    [0] => Some
    [1] => User
    [2] => Name
)
Array
(
    [2] => user.mail@address
)
Related