Рекурсия в regexp

LameRoy

Guest
Рекурсия в regexp

Привет народ. У меня такая вот проблема. Я пользуюсь вот таким регеэкспом для деления на таблицы:

preg_match_all("|(<table.*>(.*)</table>)|Uis", $l, $matchess);

Проблема возникает когда есть вложенные таблицы, получается белиберда. как сделать чтобы функция была рекурсивной? т.е. парсила и таблицы в таблице.
 

Profic

just Profic (PHP5 BetaTeam)
Есть таке дело в pcre, (?R) называется, но пользовать им можно только когда понимаешь, что делаешь иначе будут тормоза и/или неправильная работа

В твоём примере скорее всего будет работать конструкция типа
PHP:
preg_match_all ('~<table.*>((?>.*)(?:(?R)*.*)*)</table>|Uis~', $str, $m);
но вот насколько быстро она будет работать (несмотря на мою попытку оптимизировать)...
Кстати, не рекоммендую эту строку комментровать любым однострочным комментом :) Т.к. в ней встречается магическая для PHP строка ?> :)
Да и еще, конструкции с рекурсией в PCRE имеют тенденцию на больших размерах входных данных просто рушить апач.

В твоём случае имхо проще сделать немного по другому, а именно нечто типа парсера
PHP:
$level = 0;
$chunks = preg_split ('~</?table.*>|Uis~', $str, PREG_SPLIT_DELIM_CAPTURE); // остальные параметры по вкусу
и далее циклом по массиву где, если тег открывающий
$level++, а если закрывающий $level--.

В общем думай :) Это еще никому не вредило :)
 

LameRoy

Guest
блин. не работает этот рег что вы писали... пустой массив дает...

а что имелось ввиду под
"и далее циклом по массиву где, если тег открывающий
$level++, а если закрывающий $level--"?

массив то получается из одного элемента только...
 

Profic

just Profic (PHP5 BetaTeam)
1) Странно, почему не работает режим однопроходного матчинга
PHP:
$text = '<table>a<table>b</table>c</table>';
preg_match_all ('~<table.*>(.*(?:(?R)*?.*)*)</table>|Uis~', $text, $m);
print_r ($m);
Но скорость на больших текстах будет очень и очень маленькой

2) а поглядеть правильный способ вызова preg_split не судьба?
PHP:
$text = '<table>a<table>b</table>c</table>';
$chunks = preg_split ('~(</?table.*>)~Uis', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
print_r ($chunks);
 
Сверху