Попытка захвата значения в захваченном значении

Я пытаюсь разобрать данные с такой строки

"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(...) в вашей строке вы получите результаты в виде массива.

Другие вопросы по тегам