Рекурсивное регулярное выражение для сопоставления всего в скобках (PCRE) - PullRequest
0 голосов
/ 11 января 2019

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

foo(some (content)) --> some (content)

Итак, я пытаюсь сопоставить все в вызове функции, включая скобки. Вот мое регулярное выражение PCRE:

(?<name>\w+)\s*\(\K
(?<e>
     [^()]+
     |
     [^()]*
         \((?&e)\)
     [^()]*
)*
(?=\))

https://regex101.com/r/gfMAIM/1

К сожалению, это не работает, и я не очень понимаю, почему.

Ответы [ 3 ]

0 голосов
/ 11 января 2019

У меня есть простое регулярное выражение без рекурсии .

(?<=[\w ]{2}\().*(?=\))

к настоящему моменту он имеет дело с несбалансированным перентезом, но не имеет дело с несколькими функциями, которые находятся в одной строке. Это может быть сделано, если вы знаете разделители между функциями. например ; если это код Java.

Вариант 2 (обновлено для нескольких функций в строке):

(?<=[\w ]\()[^;\n]*(?=\))

Вариант 3 (допускается ; в строках):

(?<=[\w ]\()([^;\n]|".*?")*(?=\))    

Вариант 4 (экранирование строк):

(?<=[\w \n]\()(?:[^;\n"]|(?:"(?:[^"]|\\")*?(?<!\\)"))*(?=\))
0 голосов
/ 11 января 2019

Следующее регулярное выражение выполняет сопоставление без дополнительных действий:

(?<name>\w+)\s*(\((?<e>([^()]*+|(?2))+)\))

Смотрите демо здесь

Но это не соответствует следующим строкам, которые содержат несбалансированные скобки в строке в кавычках:

  • foo(bar = ')')
  • foo(bar(john = "(Doe..."))

Так что вы должны искать это:

(?<name>\w+)\s*(\((?<e>([^()'"]*+|"(?>[^"\\]*+|\\.)*"|'(?>[^'\\]*+|\\.)*'|(?2))+)\))

Смотрите демоверсию здесь

Распределение регулярных выражений:

  • (?<name>\w+)\s* Соответствие имени функции и конечных пробелов
  • ( Запуск кластера
    • \( Соответствует литералу (
    • (?<e> Начало именованной группы захвата e
      • ( Начало группы захвата # 2
        • [^()'"]*+ Соответствует любой вещи, кроме ()'"
        • | или
        • "(?>[^"\\]*+|\\.)*" Совпадение между двойными кавычками
        • | или
        • '(?>[^'\\]*+|\\.)*' Подберите любую вещь между одинарными кавычками
        • | или
        • (?2) Рекурсивная вторая группа захвата
      • )+ Повторите как можно больше, хотя бы один раз
    • ) Конец группы захвата
    • \) Совпадение ) буквально
  • ) Конец группы захвата
0 голосов
/ 11 января 2019

Шаблон вашей группы e не выполняет нужную работу, в настоящее время он сопоставляет скобки с 1 уровнем глубины, поскольку вы только один раз повторили шаблон e. Ему нужно сопоставить столько (...) подстрок, сколько имеется, и, таким образом, шаблон подпрограммы должен находиться внутри * или + количественной группы, и его даже можно «упростить» до (?<e>[^()]*(?:\((?&e)\)[^()]*)*).

Обратите внимание, что ваша группа e равна (?<e>[^()]+|\((?&e)\))*. [^()]* вокруг \((?&e)\) являются избыточными, поскольку альтернатива [^()]+ будет использовать символы, отличные от ( и ) на текущем уровне глубины.

Кроме того, вы количественно определили шаблон Group e, превратив его в группу повторных захватов , в которой текст сохраняется только во время последней итерации.

Вы можете использовать

(?<name>\w+)\s*\(\K(?<e>[^()]*(?:\((?&e)\)[^()]*)*)(?=\))

См. Демонстрационную версию regex

Детали

  • (?<name>\w+)\s*\(\K - 1+ слов, 0+ пробелов и (, которые опущены в совпадении
  • (?<e> - начало группы e
    • [^()]* - 0+ символов кроме ( и )
    • (?: - запуск группы без захвата:
      • \( - ( char
      • (?&e) - группа e шаблон повторяется
      • \) - )
      • [^()]* - 0+ символов, отличных от ( и )
    • )* - 0 или более повторений
  • ) - конец e группы
  • (?=\)) - ) должно быть непосредственно справа от текущего местоположения.
...