Попытка захвата значения в захваченном значении
Я пытаюсь разобрать данные с такой строки
"Lorem ipsum dolor sit amet, IP: 111.111.111.111, 222.222.222.222, 333.333.333.333\r\n adipiscing elit, sed do eiusmod\r\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud"
Я пытаюсь захватить значения, как это:
- сообщение:
"Lorem ipsum dolor sit amet, IP: 111.111.111.111, 222.222.222.222, 333.333.333.333\r\n adipiscing elit, sed do eiusmod\r\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud"
- IP:
"111.111.111.111, 222.222.222.222, 333.333.333.333"
Может быть произвольно много IP-адресов, включая ноль.
Я использую беглый бит с одним регулярным выражением. Это пример определения разбитого бита:
[PARSER]
Name syslog-rfc3164
Format regex
Regex /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[a-zA-Z0-9_\/\.\-]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
Time_Key time
Time_Format %b %d %H:%M:%S
Time_Format %Y-%m-%dT%H:%M:%S.%L
Time_Keep On
Благодаря Кэри и Алексею вот решение:
\A(?<whole>.*?((?<=IP: )(?<ip>(?<four_threes>\d{1,3}(?:\.\d{1,3}){3})(?:, \g<four_threes>)*)).*?)\z
https://rubular.com/r/Kgh5EXMCA0lkew
РЕДАКТИРОВАТЬ
Я понял, что в некоторых строках отсутствует шаблон "IP:...", что приводит к ошибке синтаксического анализа.
string1: "Lorem ipsum dolor sit amet, IP: 111.111.111.111, 222.222.222.222, 333.333.333.333\r\n adipiscing elit, sed do eiusmod\r\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud"
string2: "Lorem ipsum dolor sit amet, \r\n adipiscing elit, sed do eiusmod\r\n tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud"
Я попытался применить *(0 или больше) к совпадению имени группы ip, но я не смог заставить его работать. Любая идея, как я могу это сделать?
2 ответа
str = 'Lorem, IP: 111.111.111.111, 222.222.222.222, 333.333.333.333\r\n adipiscing'
r = /
\A # match the beginning of the string
(?<whole> # begin named group 'whole'
.*? # match >= 0 characters
(?<ip> # begin named group 'ip'
(?<four_threes> # begin a named group 'four_threes'
\d{1,3} # match 1-3 digits
(?: # begin a non-capture group
\. # match a period
\d{1,3} # match 1-3 digits
){3} # close non-capture group and execute same 3 times
) # close capture group 'four_threes'
(?: # begin a non-capture group
,\p{Space} # match ', '
\g<four_threes> # execute subexpression named 'four_threes'
)* # close non-capture group and execute same >= 0 times
) # close capture group 'ip'
.* # match >= 0 characters
) # close capture group 'whole'
/x # free-spacing regex definition mode
m = str.match(r)
m[:whole]
#=> "Lorem, IP: 111.111.111.111, 222.222.222.222, 333.333.333.333\\r\\n adipiscing"
m[:ip]
#=> "111.111.111.111, 222.222.222.222, 333.333.333.333"
Регулярно написано:
/\A(?<whole>.*?(?<ip>(?<four_threes>\d{1,3}(?:\.\d{1,3}){3})(?:, \g<four_threes>)*).*)/
При определении регулярного выражения в свободном интервале пространства должны быть каким-то образом защищены, иначе они будут удалены до разбора выражения. я использовал \p{Space}
, но [[:space:]]
, \s
а также [ ]
(пробел внутри класса персонажа) также может быть использован. (Все, кроме последнего, соответствуют символу пробела.) Когда регулярное выражение записывается обычным способом, можно использовать пробел, как показано выше.
\g<four_threes>
является вызовом подвыражения (поиск "Вызовы экспрессии"). Их использование экономит набор текста и снижает вероятность ошибок. Если это, третий названный захват, не нужен, его, конечно, можно заменить.
Ты можешь использовать /([0-9]_\.)+/
в качестве очень простого регулярного выражения (есть гораздо лучшие регулярные выражения IPv4).
Затем с помощью .scan(...)
в вашей строке вы получите результаты в виде массива.