Я знаю, что анализ вложенных строк или HTML лучше выполнять с помощью реального синтаксического анализатора, но в моем случае у меня есть простые шаблоны и я хотел извлечь содержимое заголовка параметра Wiki 'title' из шаблона.Мне потребовалось некоторое время, чтобы достичь этого, но благодаря инструменту регулярных выражений Ларса Олава Торвика (http://regex.larsolavtorvik.com/) и этому форуму пользователей здесь я дошел до этого. Может быть, кто-то найдет это полезным. (Мы все хотим внести свой вклад, он, не так ли? ;-) Следующий код с комментариями делает свое дело. Я должен был сделать это с осмотром утверждений, чтобы не смешивать два шаблона, если в одном из них нет заголовка.
Я пока не уверен в двух вопросах в комментариях к регулярному выражению - см. (?# Questions: …)
- если я понял рекурсивную часть на (?R)
. Это то, что он получает свое содержимое для проверки с самого определенного определенного уровня, т.е.вторая строка регулярного выражения \{\{
и последняя строка регулярного выражения \}\}
? Будет ли это правильно? И в чем разница между ++
и +
до того, как альтернатива (?R)
стенд будет работать одинаково, так что, похоже, при тестировании.
Оригинальные вики-шаблоны на странице (самые простые):
$wikiTemplate = "
{{Templ1
| title = (1. template) title
}}
{{Templ2
| any parameter = something {{template}}
}}
{{Templ1
| title = (3. template) title
}}
";
Замена:
$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);
Выходнойс заголовками, помеченными TITLE над каждым шаблоном, но только в том случае, если заголовок был:
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
Есть ли у меня какие-либо вопросы, касающиеся понимания регулярных выражений, или некоторые улучшения?Спасибо, Андреас.