PHP: preg_match для "строки из нескольких слов" + [\ s * + " "] - PullRequest
2 голосов
/ 16 июня 2020

Необходимость в строках синтаксического анализа, которые представлены в следующих возможных формах:

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

Таким образом, имя пользователя (несколько слов) всегда существует, но адрес электронной почты является необязательным и содержится в угловых скобках.

I нужно поймать из них:

  1. Имя пользователя, одна строка с несколькими словами, разделенными \ s или \ h
  2. После следующего адреса электронной почты (если существует) без угловых скобок. Если адрес электронной почты не указан, то результирующий массив подмаски должен быть пустым (но всегда существует в результате).

Я пробовал несколько вариантов

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

, но это не работает.

Спасибо всем, помогите мне.

1 Ответ

1 голос
/ 17 июня 2020

Чтобы получить все отдельные слова, разделенные \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
)
...