Как правильно обрезать строку с HTML тегами. Есть ли готовые решения?

xintrea

Новичок
Как правильно обрезать строку с HTML тегами. Есть ли готовые решения?

Здравствуйте!

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

- В строке могут попадаться HTML теги, и их символы при подсчете учитывать ненадо.
- Нельзя допускать, чтобы строка заканчивалась в середине текста тега, т.е. нельзя чтобы конец был типа "...ля<text colo"
- Все теги, открытые в строке, должны быть закрыты, пусть даже это увеличит итоговую строку
- Ну и желательно чтобы строка не оканчивалась на середине слова, а хотя бы была обрезана до ближайшего пробела (разделителя).

В общем, нужна функция, которая красиво обрезает строки, в которых встречается HTML код.

Вопрос - есть ли в природе уже готовые функции, которые умеют так делать? Может, завалялись у кого в загажниках?

На этом форуме нашел только такую тему
http://phpclub.ru/talk/showthread.php?s=&threadid=33914&highlight=%EE%E1%F0%E5%E7%E0%F2%FC+%F1%F2%F0%EE%EA%F3
но в ней ничего путного товарищу не предложили. Сообщения в ней за 2003 год, а щас 2006, может за это время появились хорошие готовые решения?

Заранее спасибо за помощь.
 

ThomLee

Новичок
Разбить на несколько этапов:
1,2,3)Обрезать html теги, если грубо - strip_tags или изящно preg_replace в мануале есть пример, неплохой.

4) Usage: string wordwrap (string str [, int width [, string break [, int cut]]])
 

xintrea

Новичок
Этот метотд испортит HTML форматирование, точнее вовсе его уберет.

А нужно чтобы HTML форматирование осталось, т. е. если в строке есть HTML-теги, их нужно оставить.

Ну например, если в первых 200 символах был тег <A HREF=...>ссылка</A>, нужно чтобы эта ссылка была видна как ссылка, а не просто как текст. То же касается и всех других тегов форматирования внешнего вида текста.
 

0xHH

Новичок
Предполагаю, можно сделать следующим образом:
1) Разбиваем строку в массив по тегам, через explode с "<".
2) С полученного массива рабиваем каждый элемент массива через explode с ">". Всё собирается в 1 массив.
3) Находим в массивы элементы, которые не имеют "<" и ">".
4) Находим их длину и находим последний нужный элемент.
5) Собираем массив через implode. (Тут ещё остаётся дозакрыть тэги для последнего нужного элемента).
 

SelenIT

IT-лунатик :)
На правах безумной идеи для несложных строк:
PHP:
preg_match('~^(?>(?><[^>]*>\s*)*[^<]){0,200}(?=\s)~s', $text, $m);
echo tidy_repair_string($m[0]);
 

xintrea

Новичок
Автор оригинала: SelenIT
На правах безумной идеи для несложных строк:
PHP:
preg_match('~^(?>(?><[^>]*>\s*)*[^<]){0,200}(?=\s)~s', $text, $m);
echo tidy_repair_string($m[0]);
Туго у меня с англицким, я что-то на php.net не понял что делает функция tidy_repair_string() ? В рунете тоже перевода нигде нет.

Есть подозрения, что она "выправляет" HTML код, проверяя правильность открытия-закрытия тегов? Во всяком случае в примере

http://ru.php.net/manual/ru/function.tidy-repair-string.php

идет исправление </i> на </p>

Было
...
<body>
<p>error</i>
</body>
...

Стало
...
<body>
<p>error</p>
</body>
...

Или у них там просто опечатка?

В любом случае, использовать Tidy библиотеку мне нельзя - проект должен работать на ранних версиях PHP4, а тут ограничение - Tidy 1.0 is just for PHP 4.3.x, while Tidy 2.0 is just for PHP 5.

Я не совсем понял, может использовать tidy_repair_string() не обязательно?
 

SelenIT

IT-лунатик :)
Это был вариант готового решения для автозакрытия оставшихся открытыми при обрезке тегов - Tidy как раз отвечает за корректное соответствие закрывающих тегов открывающим (в примере не опечатка). Конечно, в любом случае нужна "доработка напильником" (в частности, у Tidy ограничен набор поддерживаемых кодировок), но это могло бы избавить от рутинного разбора стека незакрытых тегов.
 

zerkms

TDD infected
Команда форума
опять же "на правах безумной идеи" (с)
вырезать все теги, найти последнее слово, в исходной строке найти это же слово
 

Vadim S.

Новичок
Путь решения мне видется таким:
- Вырезаете теги, складываете их в массив.
- Вырезанные из тегов слова складываете во второй массив
- В полученном "голом" тексте отрезаете 200 символов (регулярные выражения).
- Вставляете теги обратно в отрезанный текст.

Когда мне необходимо было убирать лишние пробелы в исходном коде страницы везде, кроме <script></script>
я юзал код, позаимствованный из, если правильно помню, Smarty .

Могу вечером показать своё решение. Думаю может помочь.
 

Nogrogomed

Новичок
Если с одиночными тегами проблема решаема - то если у тебя в html-тексте есть таблицы - проблему решить будет крайне сложно...
Если нет таблиц, то ИМХО, лучше пробежаться по первым 200 символам и если нашел открывающийся тег - бежать дальше и искать закрывающийся. Как только находишь последний закрывающийся тег и количество найденных символов превышает 200 - ищешь первый пробельный символ и завершаешь цикл.

Сам на эту тему не заморачиваюсь, ибо не было важной необходимости и использую strip_tags
 

litvinenko

Новичок
берешь первый встреченный тег. строка не будет короче его парного тега. и т.д.
 

Vadim S.

Новичок
PHP:
function clean_space($source)
{
preg_match_all("!<script[^>]+>.*?</script>!is", $source, $match);
preg_match_all("!<textarea[^>]+>.*?</textarea>!is", $source, $match_text);
$_script_blocks = $match[0];
$_textarea_blocks=$match_text[0];
$source = preg_replace("!<script[^>]+>.*?</script>!is", '####Vadim_S_replace####', $source);
$source = preg_replace("!<textarea[^>]+>.*?</textarea>!is", '####Vadim_S_replace_text####', $source);
$pattern = array("\n", "\r");
$replace = array('','');
$source = str_replace ($pattern, $replace, $source);

// remove all leading spaces, tabs and carriage returns NOT
// preceeded by a php close tag.

// replace script blocks
foreach($_script_blocks as $curr_block) {
$source = preg_replace("!####Vadim_S_replace####!",$curr_block,$source,1);

}
foreach($_textarea_blocks as $curr_block) {
$source = preg_replace("!####Vadim_S_replace_text####!",$curr_block,$source,1);

}
$pattern = array("\r\n//", "\n//", "\r//");
$replace= array(' //', ' //', ' //');
$source = str_replace ($pattern, $replace, $source);


return $source;
}
script, textarea заменить на то, чтоб все теги вырезались....
Хотя наверное не самый изящный вариант я думаю получится
 

Nogrogomed

Новичок
Vadim S., сколько будет работать твой скрипт, если html-текс будет достаточно большим??? Не, это не эффективный выход из ситуевины...
 

Vadim S.

Новичок
Nogrogomed, вытащить из файла только первые допустим (20 Кб) Вам религия не позволяет ?

Ваш подход ничем принципиально не отличается. Те же регулярки, только вид сбоку.

Скрипт готовый. Можете запустить и проверить сколько он будет работать на больших объёмах. Тексты в 300-400 Кб отрабатывает на раз.
Довольно редко встречаются html файлы большего объёма.



Ежели у Вас 10 Мб файл, то при каждом его открытии отрезать от него 200 символов будет только ненормальный. Это должно делаться только один раз (при первом открытии). А дальше делается контроль за изменением этого текста и т.д.
 
Сверху