2012-03-01 8 views
1

Я знаю, что синтаксический анализ вложенных строк или HTML лучше выполняется с помощью реального анализатора, но в моем случае у меня есть простые шаблоны и вы хотите извлечь содержимое заголовка Wiki параметр 'title' из шаблона. Мне потребовалось некоторое время, чтобы добиться этого, но благодаря инструменту regex Lars Olav Torvik (http://regex.larsolavtorvik.com/), и этот форум пользователя здесь я получил. Может быть, кто-то сочтет это полезным. (Мы все хотим внести свой вклад, он, не так ли? ;-) Следующий код, аннотированный комментариями, делает трюк. Я должен был сделать это, взглянув вокруг утверждений, чтобы не смешивать два шаблона, и в одном из них нет названия.Анализ сбалансированных вложенных шаблонов вики и извлечение содержимого строки одной строки с помощью regexp

Я еще не уверен в двух вопросах в комментариях к регулярному выражению - см. (?# Questions: …) -if Я понял рекурсивную часть на (?R). Является ли он, что он получает свой контент для проверки с самого внешнего определенного уровня, то есть второй строки регулярного выражения \{\{ и последней строки регулярного выражения \}\}? Правильно ли это? И в чем разница между ++ и + перед альтернативой (?R) стенд работает одинаково, поэтому кажется, что его тестировали.

  1. В origninal шаблоны вики на странице (самый простой):

    $wikiTemplate = " 
    {{Templ1 
    | title = (1. template) title 
    }} 
    
    {{Templ2 
    | any parameter = something {{template}} 
    }} 
    
    {{Templ1 
    | title = (3. template) title 
    }} 
    "; 
    
  2. Замена:

    $wikiTemplate = preg_replace(
        array(
        // tag all templates with START … END and add a TITLE-placeholder before 
        // and take care of balanced {{ … }} recursiveness 
        "@(?s) (?# switch to dotall match, i.e. also linebreaks) 
         \{\{ (?# find two {{) 
         (?: (?# group 1 as a non-backreferenced match ) 
         (?: (?# group 2 as a non-backreferenced match ) 
          (?! (?# in group 1 anything but not {{ or }}) 
          \{\{ 
          | (?# or) 
          \}\} 
         ) 
          . 
         )++ (?# Question: what is the differenc between ++ and + here?) 
         | (?# or) 
         (?R) (?# is it recursive of what is defined in the outermost, 
           i.e. 2nd regexp line with \{\{ and last line with \}\} 
           Question: is that here understood correctly?) 
        ) 
         * (?# zero or many times of the inner regexp defintions) 
         \}\} (?# find two }}) 
        @x",// x-extended → ignore white space in the pattern 
        // replace TITLE by single line content of title parameter 
        "@ 
         (?<=TITLE) (?# TITLE must preceed the following linebreak but is not 
            backreferenced within \\0, i.e. the whole returned match) 
         ([\n\r]+) (?#linebr in 1 may also described as . because of 
            s-modifier dotall) 
         (?:  (?# start non-backreferenced match) 
         .  (?# any character but not followed by START) 
         (?!START) 
        )+  (?# multiple times) 
         (?:  (?# start non-backreferenced match) 
         \|\s*title\s*=\s* (?#find the parameter '| title = ') 
        ) 
         ([^\r\n]+) (?#get title now to \\2 but exclude the line break. 
            Note it is buggy when there is no line break) 
         (?:  (?# start non-backreferenced match) 
         .  (?# any character but not followed by END) 
         (?!END) 
        ) 
         +  (?# multiple times) 
         .  (?# any single character, e.g. the last because as all 
           stuff before captures anything not followed by END) 
         (?:END) (?#a not backreferenced END) 
        @msx", // m-multiline, s-dotall match also linebreaks, 
          // x-extended → ignore white space in the pattern 
    ), 
        array(
        "TITLE\nSTART\\0END", // \0 is the whole returned match, i.e. the template 
        # replace the TITLE to TITLEtitle contentTITLE… 
        "\\2TITLE\\0", 
    ), 
        $wikiTemplate 
    ); 
    print_r($wikiTemplate); 
    
  3. Выход затем с названиями меченых по названию над каждым шаблоном, но только в случае наличия названия:

    TITLE(1. template) titleTITLE 
    START{{Templ1 
    | title = (1. template) title 
    }}END 
    
    TITLE 
    START{{Templ2 
    | any parameter = something {{template}} 
    }}END 
    
    TITLE(3. template) titleTITLE 
    START{{Templ1 
    | title = (3. template) title 
    }}END 
    

Любой внутри для моих вопросов, связанных с регулярным выражением понимания, или некоторые улучшения? Спасибо, Андреас.

ответ

0

++ является притяжательным квантором. Если вы добавите какой-либо квантификатор повторения (+, *, {...}) с +, он получает притяжательный. Это означает, что механизм регулярных выражений не будет возвращаться и повторять меньше повторений, как только он покинет повторение в первый раз. Поэтому они в основном делают повторение атомной группой. Иногда это оптимизация, и иногда это действительно имеет значение. Вы можете сделать очень хороший reading here.

А насчет второго вопроса да(?R) будет просто пытаться соответствовать полный рисунок снова. Для этого есть good article, который можно найти в документации PHP PCRE.

По другим вопросам, лучше спросить об этом может быть на Code Review.

+0

Только теперь я понимаю, сколько лет этот вопрос ... –

+0

Не имеет значения, сколько лет вопрос, спасибо в любом случае ;-) –