Regex необязательные группы захвата в любом порядке - PullRequest
0 голосов
/ 28 февраля 2020

Я хотел бы захватывать группы на основе последовательного появления совпадающих групп в любом порядке. И когда один тип набора повторяется без альтернативного типа набора, альтернативный набор возвращается как ноль.

Я пытаюсь извлечь имена и электронные письма на основе следующего регулярного выражения:

Для имен, два последовательных заглавных слова:

[A-Z][\w]+\s+[A-Z][\w]+

Для электронных писем:

\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b

Пример текста:

John Doe john@doe.com random text
Jane Doe random text jane@doe.com
jim@doe.com  more random text tim@doe.com Tim Doe

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

^(?=(?:.*([A-Z][\w]+\s+[A-Z][\w]+))?)(?=(?:.*(\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b))?).*

И результаты пропускают элементы, в которых несколько контактов находятся в одной строке:

[
  ["John Doe", "john@doe.com"],
  ["Jane Doe", "jane@doe.com"],
  ["Tim Doe", "tim@doe.com"],
]

Когда я ищу следующее:

[
  ["John Doe", "john@doe.com"],
  ["Jane Doe", "jane@doe.com"],
  [nil, "jim@doe.com"],
  ["Tim Doe", "tim@doe.com"],
]

Мои навыки в регулярных выражениях ограничены, и я начал использовать регулярные выражения, потому что это казалось лучшим инструментом для сопоставления имен и адресов электронной почты.

Является ли регулярное выражение лучшим инструментом для решения подобных задач или есть более эффективные альтернативы, использующие циклы, если мы извлекаем сотни контактов таким образом?

Ответы [ 2 ]

2 голосов
/ 28 февраля 2020

Вот переписывание идеи @ wp78de в синтаксис Ruby regexp:

regexp = /
    (?<name>
      [A-Z][\w]+\s+[A-Z][\w]+
    ){0}
    (?<email>
      \b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}\b
    ){0}

    (?:
      \g<name> (?:\w*\s)* \g<email>
    | \g<email> (?:\w*\s)* \g<name>
    | \g<email>
    )
/x

text = <<-TEXT
John Doe john@doe.com random text
Jane Doe random text jane@doe.com
jim@doe.com  more random text tim@doe.com Tim Doe
TEXT

p text.scan(regexp)
# => [["John Doe", "john@doe.com"],
# =>  ["Jane Doe", "jane@doe.com"],
# =>  [nil, "jim@doe.com"],
# =>  ["Tim Doe", "tim@doe.com"]]
2 голосов
/ 28 февраля 2020

Ваш текст уже слишком случайный, чтобы сделать эту работу. Еще больше имен и электронных писем очень трудно запоминать время от времени. Более продвинутый шаблон электронной почты только немного помог бы. Существуют не только необычные адреса электронной почты, но и все виды шаблонов диких имен.
Что насчет Дарси Блая, Маркуса-Энтони Рейда, Ли З, и это, вероятно, самые простые примеры.

Итак, вы должны сделать много предположений и не будете полностью удовлетворены, если не будете использовать более продвинутые методы, такие как обработка естественного языка.

Если вы настаиваете на своем подходе, я придумаю это (беззубое) чудовище:

([A-Z]\w+ [A-Z]\w+)(?:\w* )*([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})|
([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})(?:\w* )*([A-Z]\w+ [A-Z]\w+)|
([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})

Порядок групп чередования важен, чтобы иметь возможность перехватить шальные сообщения.

Демонстрация

PS: Демонстрация I использует сброс ветви для захвата только в группах 1 и 2. Однако похоже, что Ruby 2.x не поддерживает группы сброса веток. Итак, вам нужно проверить все 5 групп на предмет значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...