Как стать автором
Обновить

Комментарии 11


<?php

preg_match_all('/<(\\w+)>.*?<\\1>.*?<\\/\\1>.*?<\\/\\1>/', 'xxx <code>Что-то тут есть а <code>это</code> выделено еще раз</code> xxxyyyy', $a);
var_export($a);

?>
Сорри, забыл объяснить, как работает: .*? - это нежадный квантификатор, то есть такой, который захватывает только минимум того, что может, в отличие от .*

Если Вам не PHP надо, до данный регексп должен сработать и в других средах, просто надо будет оккуратно разобраться с бэкслешами и ограничителями "/".
Блин, туплю, Вы ж сами написали про .*?
C новым годом =)))
там было не .*? , а:
<code>.*?</code>

а если вложенность тройная? четвертная?
частные случаи это хорошо, но когда есть 100% уверенность что будет только так:(
пример:( :

<code>
раз
<code>два</code>
три
<code>четыре</code>
<code>пять-<code>Адын</code></code>
</code>

хочется регулярку умеющую подсчитывать совпадений и проверять каких из них больше
Для этого одними регекспами не обойдешься, у них же нет стека. Придется пользоваться помощью процедурного языка.
Рекурсивную функцию надо писать.

Через регулярку тоже можно... но сложно и надо заранее знать сколько максимум вложений может быть. Некузявый вариант.

Также бы в сторону DOM советовал бы посмотреть.
Использовать модули XML. В perl, к примеру, есть для этого XML::Parser. Представляет весь документ в виде большого хеша, а с хешами мы работать умеем.
preg_replace_callback
В Perl и PHP есть поддержка рекурсивных паттернов. Очень помогает, к примеру, для создания регекспов, улавливающих выражение с правильно вложенными скобками.

Подробнее - в документации PHP: http://www.php.net/manual/en/reference.pcre.pattern.syntax.php (см. раздел "Recursive Patterns").

----------------------------------------
<?php
$str = "<code>
one
<code>two</code>
three
<code>four</code>
<code>five-<code>one</code></code>
</code>";

$re = "!
<(\w+)> # открывающий тэг
(?> # once-only, так будет быстрее
[^<]+ # допустим, внутри не должно быть других тэгов
| (?R) # кроме того, который нам сначала попался (рекурсивно повторять весь паттерн)
)+
</\\1> # закрывающий тэг
!xs";

preg_match_all($re, $str, $regs);
print_r($regs);
----------------------------------------

(Прошу извинить за ужасное форматирование — не могу понять, почему не получилось в тексте комментария использовать HTML-тэги; видимо, кармой не вышел.)
Действительно кармой не вышел. Поправил. Решение правильное, но есть но: рекурсивные регулярные выражения могут работать жутко медленно, так что если вам не хочется чтобы ваш сервер можно было заDOSить с одной машины, то лучше всё-таки тупо пройтись по строке и посчитать количество <code>/</code>. Если это нужно для разбора каких-нибудь шаблонов, которые удалённый пользователь не вводит - решение годится...
Не предназначены регулярные выражения для разбора тегов. А все пытаются их здесь использовать. Нужно написать свой парсер для своей грамматики тегов. Для начала описать её формально. А потом почитать что такое lexer и parser и как эта абстракция помогает в решении задачи.

Или, если синтаксис тегов является подмножеством XML, использовать любой готовый парсер XML.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории