Ключевые слова:rss, web, perl, regex, (найти похожие документы)
From: jkeks <jkeks@mail.ru.>
Newsgroups: email
Date: Mon, 17 May 2005 14:31:37 +0000 (UTC)
Subject: Удаляем последний блок RSS через regexp, используя Perl
Давно не было ничего интересного..
Дак вот а я тут сел за RSS, ну и думаю.
Задача такая была:
Надо из текста убрать небольшой блок.
Как это сделать минимальным кодом ?
Правильно надо использовать регекспы, т.е. поиск по шаблону.
Почему использование циклов тут неприемлимо ?
Ну просто потому что лучше один раз долететь, чем бегать каждый раз.
Для начала пример:
.1..
<item>
.2..
</item>
<item>
.3..
</item>
<item>
.4..
</item>
</channel>
.5..
Отсюда надо удалить последний блок <item>...</item>
В сабстрингах решение было бы такое:
1. Ищем вхождение строки </item>
2. После него все копируем
3. Ищем вхождение в последний <item>
4. Обрезаем вместе с ним же
5. Склеиваем получившиеся строки
Представляете код такой программы ?
Можно кстати сделать и по другому, ведь тут миллиард вариантов, но все
они будут содержать как минимум 4-5 действий. и к тому же не совсем
простых 8)
Ну да пофигу.. я уверен что регекспом можно решить задачу куда прощще,
и не факт что эффективнее, но это уже меня не волнует.
Для меня важен минимализм и красота кода.
Время я кстати пока постратил на решение проблеммы без инета и
литературы около3-х часов. Согласитесь - немало, но сделать ничего не
смог.
Как вы заметили я вписал последний кусок тэга </channel>
это условие всегда верно, точнее верно в таком виде:
<\/item>\s+<\/channel>
тэг внутри текста </channel> - встречается один раз, это факт.
Поэтому упрощщая себе задачу я склонен изначально к поиску последнего
<item> и любого </channel>
Первое что пришло мне на ум:
$a=~s/(<\/item>.+?)<\/channel>/<\/channel>/sm;
Но почему-то эта строка не работает..
не работает и
$a=~/(<item>)(.*?)(<\/channel>)/s;
print $2;
Наконец упал shttp пришлось качать новую версию.
Ну вроде не падает больше пока..
а результатом выходит: .2.. .3.. .4..
Мыслю я вроде логически, но видно не все учел.
Начал рыть Perl Cookbook и Холзнера.
Проблемма в том, что я не могу отловить именно последний <item>, а
затем взять содержимое между чем-то..
Прошел час..
текущий вариант:
if ($a=~/<item>([<>\ \/.0-9a-z\s]*)<\/channel>/s )
{
print 'Iaoae';
print $1;
но это ерунда, это я не могу разобраться с шаблонами
Данная конструкция работает в случае если предпоследний блок
<item>..</item> будет чем-то уникален и я буду это знать.
Это меня не устраивает.
Тут подумал у меня 2 варианта: Я могу искать текст между
item..не item..channel
Как я щас и делаю
А можно найти все блоки item и взять последний.
Если идти таким путем, то у нас работает элементарный запрос:
$revdabiz=($content=~/<item>.+?<\/item>/sg)[-1];
Результат:
<item>
.4..
</item>
и нет привязки к channel, что может и плохо а может и хорошо.
В данном случае мы имеем возможность впринципе обратиться к любому
блоку по номеру, а так же к первому и последнему, к четному и
нечетному и т.п.
Хоть по функции
Ограничение - между ограничителями не должно быть слов <item> </item>
Впрочем это уже задача отображающего фильтра.
Наконец как же мы вырежем текст-то ? мы же только нашли блок!
Удаляем блок теперь так:
$a=~s/$revdabiz\s+//;
Итого наш код который удаляет последний RSS блок очень краток, прост,
расширяем, и удобен (в $a - находится содержимое rss файла):
$revdabiz=($a=~/<item>.+?<\/item>/sg)[-1];
$a=~s/$revdabiz\s+//; # тут новый rss с удаленным последний блоком
Кое что необычное на http://revda.biz и http://revda.info
jkeks