Я пытаюсь проанализировать подмножество веб-страницы с регулярным выражением просто для удовольствия. Было весело, пока я не столкнулся со следующей проблемой. У меня есть параграф, как показано ниже;
foo: 1, 2, 3, 4 and 5.
bar: 1, 2 and 3.
Я пытаюсь получить числа в первой строке абзаца, начиная с foo:, применяя следующее регулярное выражение:
foo:(?:\s(\d)(?:,|\sand|\.))+
Это соответствует приведенной выше строке, но захватывает только последнее вхождение группы захвата, которой является 5.
Как я могу захватить все числа в абзаце, начиная с foo: до первого появления ., используя один шаблон регулярного выражения.
Да, но не нужно использовать \K, подойдет s.scan(/(?:foo:\s*|(?!\A)\G\s*(?:,|and)?\s*)(\d+)/). Зато s[/foo:([^.]+)/,1].scan(/\d+/) красивее выглядит.
Хотя это не повлияло на Rubular способ отображения результатов, \K предназначен для чистого представления чисел.
Этот \G сделал фокус, спасибо, но не могли бы вы опубликовать это в качестве ответа с объяснением \G и, возможно, \K? Я уже провел поиск и нашел, что он делает, но пояснительный ответ может помочь тому, кто ищет ответ для аналогичной проблемы.
Сделайте себе хеш: str.scan(/\w+:.*?\./).map { |s| [s[/\w+/].to_sym,s.scan(/\d+/)]}.to_h #=> {:foo=>["1", "2", "3", "4", "5"], :bar=>["1", "2", "3"] }
Ваше решение не отвечает всем требованиям. Во-первых, он возвращается не только для строк, начинающихся с foo:, а во-вторых, я задал вопрос, чтобы сделать это с помощью регулярного выражения Один.
Кто является владельцем «Твоего решения»? Пожалуйста, начните свои комментарии с имени пользователя человека, которому вы адресуете свой комментарий, которому предшествует "@". Посмотрите на другие вопросы SO, и вы поймете, что я имею в виду.
@CarySwoveland Думаю, в моих комментариях нет двусмысленности. Если вы прочитаете все комментарии в хронологическом порядке, их цели довольно ясны. Но буду иметь это в виду, спасибо за совет.
@revo ваше регулярное выражение решило мою проблему, спасибо.
Отлично, @revo! Опубликуйте свое решение в качестве ответа, желательно с регулярным выражением, представленным в режиме свободного интервала, с документированием каждого элемента (как я сделал в своем ответе). Вы уверены, что \K [необходим] (rubular.com/r/zfNjHXL9Rl)? Документ для Строка # сканирование говорит о необходимости \K: «Если шаблон содержит группы, каждый отдельный результат сам по себе является массивом, содержащим по одной записи для каждой группы». (т.е. этот \K не нужен). Симулятор регулярных выражений предполагает, что на самом деле это свойство MatchData. Нет?
FooBarZoo, \K можно прочитать как «забыть все, что было найдено до сих пор». Строка перед \K должна совпадать, но не является частью возвращаемого совпадения. Здесь все совпадения, но значения групп захвата не меняются.
@CarySwoveland Спасибо, я добавил ответ. Ранее я сказал, что использую \K только для чистого представления цифр в демонстрации (предыдущие комментарии). Однако я не заметил, что вывод для совпадающих частей отличается от вывода групп захвата (в regex101 это другое) с самого начала.

В этом ответе используется только одно регулярное выражение, но, по общему признанию, выполняется небольшая предварительная и пост-обработка. (Пожалуйста, позвольте мне немного развлечься. Я действительно думаю, что здесь может быть некоторая учебная ценность.)
str = "foo: 1, 2, 34, 4 and 5. and 6."
r = /
\d+ # match one or more digits
(?=[^.]+:oof\z) # match one or more digits other than a period, followed
# by ":oof" at the end of the string, in a positive lookahead
/x # free-spacing regex definition mode
str.reverse.scan(r).join(' ').reverse.split
#=> ["1", "2", "34", "4", "5"]
Шаги следующие.
s = str.reverse
#=> ".6 dna .5 dna 4 ,43 ,2 ,1 :oof"
a = s.scan r
#=> ["5", "4", "43", "2", "1"]
b = a.join(' ')
#=> "5 4 43 2 1"
c = b.reverse
#=> "1 2 34 4 5"
c.split
#=> ["1", "2", "34", "4", "5"]
Если совпадений нет, возвращается пустой массив.
Итак, почему все задним ходом? Это позволяет мне использовать положительный смотреть вперед, который, в отличие от положительного смотреть за, разрешает совпадения переменной длины.
Данные повторяющейся группы захвата не хранятся отдельно на большинстве языков программирования, поэтому вы не можете ссылаться на них по отдельности. Это веская причина использовать якорь \G. \G заставляет совпадение начинаться с того места, где закончилось предыдущее совпадение, или оно будет соответствовать началу строки так же, как \A.
Итак, нам нужна его первая возможность:
(?:foo:|\G(?!\A))\s*(\d+)\s*(?:,|and)?
Авария:
(?: Запустить группу без захвата
foo: Соответствует foo:| Или\G(?!\A) Продолжить матч с того места, где закончился предыдущий) Конец NCG\s* Любое количество пробельных символов(\d+) Совпадение и захват цифр\s* Любое количество символов whitespae(?:,|and)? Дополнительный , или andЭто регулярное выражение начнет сопоставление при встрече foo во входной строке. Затем пытается найти следующую цифру, которая предшествует запятой или and (вокруг цифр разрешены пробелы).
Токен \K сбросит совпадение. Это означает, что он отправит сигнал движку, чтобы забыть все, что было найдено до сих пор (но сохранить все, что было захвачено), а затем оставит курсор прямо в этой позиции.
Я использовал \K в регулярном выражении Rubular, чтобы результирующий набор содержал не совпадающие строки, а захваченные цифры. Однако Rubular, похоже, работает иначе, и ему не нужен \K. Это совсем не обязательно.
Вы не можете в Ruby без помощи
\Grubular.com/r/VKOaLEYmSI