Чтобы получить все отдельные слова, разделенные \h
, и необязательный адрес электронной почты, вы можете использовать привязку \G
для получения итеративных совпадений, утверждая позицию в конце предыдущего совпадения.
(?|^(\w+)|\G(?!^)\h+(\w+))(?:\h+<([^<>\r\n]+)>$)?
Пояснение
(?|
Группа сброса ответвлений (Чтобы сохранить слова в $matches[1]
) ^(\w+)
Начало строки, сопоставление 1+ символов слова в группе 1 |
Или \G(?!^)
Подтвердить позицию в конце предыдущего совпадения, не в начале \h+(\w+)
Сопоставить 1+ горизонтальных пробельных символов в группе 1
)
Закрыть группу сброса ветвления (?:
Группа без захвата \h+
Соответствует 1+ горизонтальным пробелам <([^<>\r\n]+)>$
Захватить адрес электронной почты между <>
в группе 2 в конце строки
)?
Закройте группу без захвата и сделайте ее необязательной
Regex demo | Php demo
Используйте preg_match_all , чтобы получить все значения.
Флаг по умолчанию - PREG_PATTERN_ORDER
, который:
Заказывает результаты так, чтобы $ match [0] был массивом полных совпадений с шаблоном, $ match [1] - массивом строки, соответствующие первому вложенному шаблону в скобках, и т. д.
Слова находятся в $matches[1]
, а электронное письмо - в $matches2
Если электронное письмо отсутствует, массив будет там, но пустой.
Вы можете использовать array_filter , чтобы удалить пустые записи из массива электронной почты.
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]));
}
Вывод
Array
(
[0] => Some
[1] => User
[2] => Name
)
Array
(
)
Array
(
[0] => Some
[1] => User
[2] => Name
)
Array
(
[2] => user.mail@address
)