Вложенное регулярное выражение ... Я не знаю! - PullRequest
2 голосов
/ 17 октября 2010

Я довольно невежествен, когда дело доходит до PHP и регулярных выражений, но я пытаюсь починить сломанный плагин для моего форума.

Я бы хотел заменить следующее:

<blockquote rel="blah">foo</blockquote>

С

<blockquote class="a"><div class="b">blah</div><div class="c"><p>foo</p></div></blockquote>

На самом деле, эта часть проста, и я уже частично исправил плагин, чтобы сделать это. Следующее регулярное выражение используется в вызове preg_replace_callback() для выполнения замены:

/(<blockquote rel="([\d\w_ ]{3,30})">)(.*)(<\/blockquote>)/u

Код обратного вызова:

return <<<BLOCKQUOTE
<blockquote class="a"><div class="b">{$Matches[2]}</div><div class="c"><p>{$Matches[3]}</p></div></blockquote>
BLOCKQUOTE;

И это работает для моего приведенного выше примера (не вложенные цитаты). Однако , если кавычки вложены, например, в следующем примере:

<blockquote rel="blah">foo <blockquote rel="bloop">bar ...maybe another nest...</blockquote></blockquote>

Это не работает. Итак, мой вопрос, как я могу заменить все вложенные blockquotes, используя комбинацию regex / PHP? Я знаю, что в PHP возможны рекурсивные шаблоны с (?R); следующее регулярное выражение извлечет все вложенные цитаты из строки, содержащей их:

/(<blockquote rel="([\d\w_ ]{3,30})">)(.*|(?R))(<\/blockquote>)/s

Но с этого момента я не совсем уверен, что делать в обратном вызове preg_replace_callback(), чтобы заменить каждую вложенную цитату на вышеуказанную замену.

Буду признателен за любую помощь.

Ответы [ 2 ]

6 голосов
/ 17 октября 2010

Простой ответ: вы не можете сделать это с помощью регулярных выражений. Язык вложенных тегов (или parens, или скобок, или чего-либо) произвольной глубины не является регулярным и, следовательно, не может быть сопоставлен с выражением регулярного . Я бы посоветовал вам использовать анализатор DOM или - если это абсолютно необходимо по какой-то странной причине - написать собственную схему синтаксического анализа.

Сложный ответ заключается в том, что вы могли бы сделать это с помощью какого-то очень уродливого, хакерского регулярного выражения и PHP-кода, но я бы не советовал это быть честным.

См. Также: Хомская иерархия .

Также см. Также:

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

Нет прямой поддержки рекурсивных замен, и preg_replace_callback() не особенно полезен в этом случае.Но ничто не мешает вам сделать замену за несколько проходов.Первый проход заботится о самых внешних тегах, а последующие проходы направляются внутрь.Необязательный аргумент $count сообщает вам, сколько замен было выполнено за каждый проход;когда он достигает нуля, все готово.

$regex = '~(<BQ rel="([^"]++)">)((?:(?:(?!</?+BQ\b).)++|(?R))*+)(</BQ>)~s';
$sub = '<BQ class="a"><div class="b">$2</div><div class="c"><p>$3</p></div></BQ>';
do {
  $s = preg_replace($regex, $sub, $s, -1, $count);
} while ($count != 0);

Посмотрите это в действии на ideone.com

...