Какое выражение reg patten мне нужно, чтобы все совпадало между {{и}} - PullRequest
1 голос
/ 14 октября 2010

Какое выражение patten мне нужно, чтобы все совпадало между {{и}}

Я пытаюсь разобрать Википедию, но я заканчиваю с orphan}} после выполнения кода rexex.Вот мой PHP-скрипт.

<?php

$articleName='england';

$url = "http://en.wikipedia.org/wiki/Special:Export/" . $articleName;
ini_set('user_agent','custom agent'); //required so that Wikipedia allows our request.

$feed = file_get_contents($url);
$xml = new SimpleXmlElement($feed);

$wikicode = $xml->page->revision->text;



$wikicode=str_replace("[[", "", $wikicode);
$wikicode=str_replace("]]", "", $wikicode);
$wikicode=preg_replace('/\{\{([^}]*(?:\}[^}]+)*)\}\}/','',$wikicode);

print($wikicode);

?>

Мне кажется, проблема в том, что я вложил {{и}}, например,

{{что-то {{что-то еще {{что-то новое}} {{что-тостарый}} что-то голубое}} что-то зеленое}}

Ответы [ 5 ]

4 голосов
/ 14 октября 2010

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

\{\{(.*?)\}\}

Большинство разновидностей регулярных выражений рассматривают скобку { как буквальный символ, если только она не является частью оператора повторения, подобного {x,y}, что здесь не так.Таким образом, вам не нужно экранировать его с помощью обратной косой черты, хотя выполнение этого даст тот же результат.

Так что вы также можете использовать:

{{(.*?)}}

Пример:

$ echo {{StackOverflow}} | perl -pe 's/{{(.*?)}}/$1/'
StackOverflow

Также обратите внимание, что .*, который соответствует любому символу (кроме новой строки), используется здесь не жадным способом.Поэтому он будет стараться соответствовать как можно меньше.

Пример:

В строке '{{stack}}{{overflow}}' она будет соответствовать 'stack', а не 'stack}}{{overflow'.
Если вы хотите более позднее поведение, вы можете изменить .*? на .*, делая состязание жадным.

2 голосов
/ 14 октября 2010

Ваша правка показывает, что вы пытаетесь выполнить рекурсивное сопоставление, которое сильно отличается от исходного вопроса. Если бы вы не просто удалили сопоставленный текст, я бы посоветовал вам вообще не использовать регулярные выражения, но это должно делать то, что вы хотите:

$wikicode=preg_replace('~{{(?:(?:(?!{{|}}).)++|(?R))*+}}~s',
                       '', $wikicode);

После того, как первый {{ соответствует открывающему разделителю, (?:(?!{{|}}).)++ поглощает все до следующего разделителя. Если это еще один открывающий разделитель, (?R) вступает во владение и снова применяет все регулярные выражения, рекурсивно.

(?R) примерно так же нестандартен, как и возможности регулярных выражений. Он уникален для библиотеки PCRE, которая является основой PHP-выражения. У некоторых других ароматов есть свои собственные способы сопоставления рекурсивных структур, все они сильно отличаются друг от друга.

0 голосов
/ 14 октября 2010

Жадная версия для получения кратчайшего совпадения -

\{\{([^}]*(?:\}[^}]+)*)\}\}

(Для сравнения, со строкой {{fd}sdfd}sf}x{dsf}}, ленивая версия \{\{(.*?)\}\} требует 57 шагов для сопоставления, а моя версия - только 17 шагов. Это предполагает, что отладочный вывод Regex Buddy может быть доверенным.)

0 голосов
/ 14 октября 2010

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

\{\{(([^}]|}[^}])*)}}

Внутренний ([^}]|}[^}])* используется для сопоставления только последовательностей из нуля или более произвольных символов, которые не содержат последовательность }}.

0 голосов
/ 14 октября 2010

\{{2}(.*)\}{2} или, чище, с поиском ответов (?<=\{{2}).*(?=\}{2}), но только если ваш движок регулярных выражений их поддерживает.

Если вы хотите, чтобы ваш матч остановился на первом найденном }} (т.е. не жадном) вы должны заменить .* на .*?.

Также вы должны принять во внимание настройки согласования одной строки вашего движка, так как в некоторых из них . не будет совпадать с символами новой строки по умолчанию.Вы можете включить одну строку или использовать [.\r\n]* вместо .*.

...