Как построить регулярное выражение Ruby, которое соответствует первому примеру многосимвольного шаблона? - PullRequest
0 голосов
/ 16 мая 2018

У меня есть многострочный фрагмент кода ruby, из которого мне нужно извлечь аргументы для конкретного метода, в этом примере метода foo:

code = "qux = define {\n  foo an arbitrary statement\n    that could go on for \n    several lines\n  bar 42\n  baz\43\n}"

Из этого я хотел бы извлечь an arbitrary statement\n that could go on for \n several lines.Для этого я хотел бы захватить все между foo и первым экземпляром /^\s{2}\w+/, отмечая начало следующего метода и его аргумент.

Среди моих неудач сделать это (в пределах code.match(<example regex here>)[1]) являются:

/foo(.*)\s{2}\w+/m
/^\s+foo(.*)^\s{2}\w+/m
/\n\s+foo(.*)\n\s{2}\w+/m
/\n\s+foo(.*)\n\s{2}\w+?/m

и так далее.Кажется, никто не возвращает шаблон «заявления», который я ищу.Ленивые / жадные операторы имеют некоторый эффект, но никогда не удаляют всю строку после целевого шаблона foo(.*).

Есть предложения?

1 Ответ

0 голосов
/ 16 мая 2018
r = /
    (?<=     # begin a positive lookbehind
      \b     # match a (zero-width) word break
      foo    # match string
      [ ]    # match a space
    )        # close positive lookbehind
    .*?      # match zero or more chars, non-greedily
    (?=      # begin a positive lookahead
      \n     # match newline char
      [ ]{2} # match two spaces
      \w     # match a word char
    )        # close positive lookahead
    /xm      # free-spacing and multiline modes

code[r]
  #=> "an arbitrary statement\n    that could go on for \n    several lines"

Обычное выражение для регулярного выражения выглядит следующим образом.

/(?<=\bfoo ).*?(?=\n  \w)/m

Обратите внимание, что в режиме свободного пробела я сопоставлял пробелы с классом символов, содержащим один пробел ([ ]). Если бы я использовал пробелы, как я делал в регулярном выражении непосредственно выше, они были бы удалены, потому что я использовал режим свободный интервал для определения регулярного выражения, которое игнорирует пробелы.

Важно, чтобы выражение, которое захватывает возвращаемую строку, было нежадным (.*? вместо .*). Если бы он был жадным (.*), мы получили бы ошибочный результат, как показано на следующем примере:

str = "foo oh my\n  a\n  b\n  c"
str[r]
  #=> "oh my"
str[/(?<=\bfoo ).*(?=\n  \w)/m]
  #=> "oh my\n  a\n  b"

В жадном случае .* поглощает столько, сколько в банке, пока не дойдет до последнего возможного совпадения положительного взгляда (?=\n \w), а именно "\n c".

разрыв слова (\b) должен гарантировать, что мы не совпадаем, например, "snafoo". Требуется, чтобы "foo" предшествовал несловесный символ или был первый символ строки.

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

code[/\bfoo \K.*?(?=\n  \w)/m]
  #=> "an arbitrary statement\n    that could go on for \n    several lines"

\K можно прочитать, "отбросить все совпадения при возврате сопоставленной строки". То есть, часть перед \K должна совпадать; он просто не используется при формировании совпавшей строки, которая возвращается.

Последний способ написать регулярное выражение - использовать группу захвата.

code[/\bfoo (.*?)\n  \w/m, 1]
  #=> "an arbitrary statement\n    that could go on for \n    several lines"

Интересующая строка записывается в группу захвата 1, а затем возвращается в необязательном втором аргументе String # [] .

Наконец, обратите внимание, что \w ближе к концу имеет тот же эффект, что и \w+.

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