2012-05-19 2 views
0

Этот вопрос связан с PCRE.Рекурсивный поиск PCRE с узорами

Я видел рекурсивный поиск вложенных скобок, используемых с этой конструкцией:

\(((?>[^()]+)|(?R))*\) 

Проблема с этим состоит в том, что, в то время как «[^()] +» может соответствовать любому символу, включая символ новой строки , вы вынуждены сопоставлять только односимвольные символы, такие как фигурные скобки, скобки, знаки препинания, отдельные буквы и т. д.

То, что я пытаюсь сделать, это заменить символы '(' и ')' ЛЮБОЙ шаблон (например, такие ключевые слова, как «BEGIN» и «END»).

я пришел с помощью следующей конструкции:

(?xs) (?# <-- 'xs' ignore whitespace in the search term, and allows '.' 
       to match newline) 
(?P<pattern1>BEGIN) 
(
    (?> (?# <-- "once only" search) 
     (
     (?! (?P=pattern1) | (?P<pattern2>END)). 
    )+ 
    ) 
    | (?R) 
)* 
END 

Это действительно будет работать на то, что выглядит следующим образом:

BEGIN <<date>> 
    <<something> 
    BEGIN 
     <<something>> 
    END <<comment>> 
    BEGIN <<time>> 
     <<more somethings>> 
     BEGIN(cause we can)END 
     BEGINEND 
    END 
    <<something else>> 
END 

Это успешно соответствует любой вложенной паре begin..end.

Я создал именованные шаблоны pattern1 и ТЕСТ2 для НАЧАТЬ и END соответственно. Использование pattern1 в поисковом запросе отлично работает. Тем не менее, я не могу использовать pattern2 в конце поиска: мне нужно написать 'END'.

Любая идея, как я могу переписать это регулярное выражение, поэтому мне нужно только указать шаблоны один раз и использовать их «везде» внутри кода? Другими словами, мне не нужно писать END как в середине поиска, так и в самом конце.

+0

Hello. Был ли мой ответ какой-либо помощи? Если нет, можете ли вы объяснить, как? – Kobi

+0

@Kobi: При взгляде на ваш пример (http://regex101.com/r/aG7wP4) он соответствует только самому внешнему блоку, если один из шаблонов несовместим (одно из ключевых слов BEGIN или END написано с ошибкой или опущено). – OnlineCop

ответ

3

Для дальнейшего расширения на @Kobis ответ, пожалуйста, см следующее регулярное выражение:

(?xs) 
(?(DEFINE) 
     (?<pattern1>BEGIN) 
     (?<pattern2>END) 
) 
(?=((?&pattern1) 
(?: 
    (?> (?# <-- "once only" search) 
     (?: 
     (?! (?&pattern1) | (?&pattern2)) . 
    )+ 
    )* 
    | (?3) 
)* 
(?&pattern2) 
)) 

Это регулярное выражение позволит даже получать данные для каждого отдельного блока данных! Используйте третью обратную ссылку, так как первые два были определены в блоке определений.

Демонстрация: http://regex101.com/r/bX8mB6

0

Это выглядит как хороший вариант для блока (?(DEFINE)), который используется для создания таких конструкций. Пример из Perl будет:

(?xs) 
(?(DEFINE) 
     (?<pattern1>BEGIN) 
     (?<pattern2>END) 
) 
(?&pattern1) 
(
    (?> (?# <-- "once only" search) 
     (
     (?! (?&pattern1) | (?&pattern2)). 
    )+ 
    ) 
    | (?R) 
)* 
(?&pattern2) 

Пример: http://ideone.com/8o9cg

(обратите внимание, я не знаю ни Perl, и не мог заставить его работать на PHP на любой из интернет-тестеров)

Смотрите также: http://www.pcre.org/pcre.txt (ищи (?(DEFINE) 0 это не выглядит, как они есть страницы)


низкотехнологичного решение, которое работает на большинстве вкусов использовать предпросмотр в начале шаблона:

(?=.*?(?P<pattern1>BEGIN)) 
(?=.*?(?P<pattern2>END)) 
... 
(?P=pattern1) (?# should work - it was captured) 
Смежные вопросы