Модераторы: Aliance, skyboy, MoLeX, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Удаление тэгов с частично известным содержимым 
V
    Опции темы
w1nd
  Дата 14.12.2007, 22:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вертилятор
***


Профиль
Группа: Завсегдатай
Сообщений: 1077
Регистрация: 22.3.2006
Где: Москва

Репутация: нет
Всего: 54



Есть html, из которого требуется удалить тэги, содержащие помимо всего прочего, известные ключевые слова. Пытаюсь сделать это так:
Код
<?php

$text = <<<EOF
<table>
    <tr>
        <td> ... </td>
        <td> bla-bla-bla keyword bla-bla-bla</td>
        <td> ... </td>
    </tr>
</table>

<table>
    <tr>
        <td> ... </td>
        <td> aaa </td>
        <td> ... </td>
    </tr>
</table>

<table>
    <tr>
        <td> ... </td>
        <td> bla-bla-bla keyword bla-bla-bla</td>
        <td> ... </td>
    </tr>
</table>
EOF;

echo preg_replace("#<table>(?:.*?)keyword(?:.*?)</table>#is", "", $text);

 ?>

Но удаляется всё, начиная с первого вхождения открывающего тэга и последним вхождением удовлетворяющего шаблону блока. Можно ли добиться нужного мне результата с помощью регулярных выражений?


--------------------
user posted imageuser posted image
PM MAIL ICQ   Вверх
skyboy
Дата 15.12.2007, 01:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 8
Всего: 260



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

<?php
$text = "A123456789A`B1234567890B`C123456789C`D123456789D`";
echo preg_replace("#8.*0.*2#iUs", "aaa", $text)." - нежадные по умолчанию";
echo '<br />';
echo preg_replace("#8.*0.*2#is", "aaa", $text)." - жадные по умолчанию";
 ?>

выводит два варианта: с жадными по умолчанию регулярными выражениями и нежадными.
вывод я ожидал такой:
Цитата

A123456789A`B1234567ааа3456789C`D123456789D` - нежадные по умолчанию
A12345678ааа23456789D` - жадные по умолчанию

но получил:
Цитата

A1234567aaa3456789C`D123456789D`- нежадные по умолчанию
A12345678ааа23456789D` - жадные по умолчанию

Т.е. ожидал, что (не)жадность будет работать в обе стороны: и в сторону окончания текста, и в сторону начала.
но для нежадных по умолчанию выражений происходит, видимо, следующее:
1. идем с первого символа, пока не встретится похожее на выражение начала(символ "8" в первой декаде цифр) // в шаблон "8"
2. дальше должно идти любое количество любых символов и символ "0"(туда попадает вся вторая декада цифр) // в шаблоне ".*0"
3. дальше должно идти любое количество любых символов и символ "2" // в шаблоне ".*2"
Вот отличие жадных и нежадных - только на шаге номер 3. Жадные берут под "любое количество любых символов" все символы подряд, включая ожидаемую "2", так как ограничением будет последняя встреченная двойка. А нежадные берут первую двойку.
Но ни жадный режим, ни нежадный не учитывают тот факт, что строку "89А`B12345678", которая совпадает с частью шаблона "8.*" можно сократить вправо до "8", и соотвествие останется, а размер уменьшится. Думаю, это для ускорения столь универсальной, но очень неповоротливой конструкции, как регулярные выржения.
Выход? не знаю. думал разобраться при помощи пре/постусловий, но почему-то не получилось.
PM MAIL   Вверх
skyboy
  Дата 15.12.2007, 02:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 8
Всего: 260



похоже, вот решение:
Код

#<table>((?<!</table>).)*keyword((?!<table>).)*</table>#is

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

<table>
    <tr>
        <td> ... </td>
        <td> aaa </td>
        <td> ... </td>
    </tr>
</table>

То, что ты хотел?
к слову, конструкция ((?!<table>).)* практически заменяет отключение механизма жадности - если вместо этого куска подставить просто ".*", то регулярка удаляет все подряд при включенной жадности по умолчанию и продолжает нормально работать при выключенной.
т.е., в принципе, регулярка должна быть вроде
Код

#<table>(?:(?<!</table>).)*keyword(?:.*)</table>#iUs
чтоб сохранить дух твоей регулярки и использовать условия (?:) вместо безусловных совпадений
PM MAIL   Вверх
w1nd
Дата 15.12.2007, 03:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вертилятор
***


Профиль
Группа: Завсегдатай
Сообщений: 1077
Регистрация: 22.3.2006
Где: Москва

Репутация: нет
Всего: 54



skyboy, "позвольте замереть в глубоком пардоне" (с) smile 


--------------------
user posted imageuser posted image
PM MAIL ICQ   Вверх
skyboy
  Дата 15.12.2007, 12:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 8
Всего: 260



к сожалению, данная конструкция далеко не универсальна: она просто предотвращает обработку таблиц одного уровня одной регуляркой. 
если же таблицы будут вложенные(то есть не чередование пар <table> + </table>, а несколько подряд идущих <talbe> без </table>), то структура страницы будет нарушена.
PM MAIL   Вверх
sTa1kEr
Дата 11.1.2008, 18:29 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 5
Всего: 146



Для вложенных таблиц будут кстати рекурсивные шаблоны. Разнес части регулярки по переменным для лучшей читаемости.
Код

$text = <<< EOF
<table>
    <tr>
    <td><table><tr><td>keyword</td></tr></table></td>
    </tr>
</table>
<table>
    <tr>
    <td> aaa </td>
    </tr>
</table>
<table>
    <tr>
    <td>Keyword: <table><tr><td>somebody</td></tr></table></td>
    </tr>
</table>
EOF;

$ot = '(.(?!<table>))*'; // Кроме открывающегося тега таблицы
$ct = '((?<!<\/table>).)*'; // Кроме закрывающегося тега таблицы
$t = "<table>$ct<\\/table>"; // Таблица без других вложенных таблиц
echo preg_replace("/<table> $ct (keyword | keyword $ot.$t | $t$ot keyword | (?R)) $ot <\/table>/isx", "", $text);

Ны выходе получаем:
Код

<table>
    <tr>
    <td> aaa </td>
    </tr>
</table>

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Тексты | Следующая тема »


 




[ Время генерации скрипта: 0.0869 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.