Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > PHP: Тексты > Как обрезать строку с форматированием |
Автор: Gold Dragon 17.4.2010, 12:14 | ||||
Собственно вопрос... Допустим существует стока с форматирование типа
Мне нужно обрезать строку и оставить допустим 150 символов. Как это можно сделать сохранив форматирование? Добавлено через 2 минуты и 49 секунд как-то странно создалась тема :( попробую продублировать Собственно вопрос... Допустим существует стока с форматирование типа
Мне нужно обрезать строку и оставить допустим 150 символов. Как это можно сделать сохранив форматирование? |
Автор: Photon 17.4.2010, 19:18 |
Ну в голову приходит только совершенно дебильный метод: проход по строке, при обнаружении открывающего тега сохранить в массиве, что он был, если нашли такой же закрывающий - удалить из массива. Как только дошли до нужной позиции - добавляем закрывающие теги на всё, что осталось в массиве тегов |
Автор: smartov 17.4.2010, 20:12 |
Рекурсивная функция, которая вырезает 150 символов, смотрит нету ли в них тегов, отрезает от изначальной строки и прибавляет к конечной еще кусок длиной в "длина тегов". И так пока текст кроме тегов не станет 150 символов. После чего надо пробежаться и закрыть все теги. |
Автор: Gold Dragon 18.4.2010, 09:42 |
а примерчик можно, а то что-то не въеду ![]() |
Автор: ArchNix 18.4.2010, 10:21 | ||
Примерчик ![]()
|
Автор: brother79 19.4.2010, 12:26 |
1) Тупо отсчитываешь 150 символов, пропуская встретивиеся теги. 2) Если последний тег не закрытый, то 2 вар-та есть, либо закрыть самому, либо обрезать весь |
Автор: Gold Dragon 19.4.2010, 13:13 |
ArchNix, попробую что за код... ![]() brother79, это не выход. Может быть куча вложенных тегов которые не закроются. И тогда весь сайт поплывёт |
Автор: Gold Dragon 20.4.2010, 08:00 |
в общем начал колдовать.. Но столкнулся с ещё одной бедой.. А если есть таблица? Тут не только нужно считать теги но и структуру считать.. В общем ужас ![]() |
Автор: SickFxck 20.4.2010, 10:10 |
Gold Dragon, какая разница — таблица у тебя или что-то другое? Какой ты алгоритм сам для себя выбрал? |
Автор: Gold Dragon 20.4.2010, 10:12 |
разница есть, например, если используются colspan или rowspan. Или что-то типа <col> у которого нет </col> |
Автор: smartov 20.4.2010, 10:45 | ||
Все теги имеют закрывающий тег. То, что для некоторых его можно не писать - это послабляющий фактор, но никак не мешает тебе его закрыть. Добавлено через 2 минуты и 6 секунд Черт, подумал и понял проблему... То есть выкусил типа
И по логике, получается, что col надо закрыть ![]() Сложно... Чуть ли не парсер писать надо. |
Автор: Gold Dragon 20.4.2010, 11:24 |
вот именно, писать парсинг... :( ну или сделать ограничения не теги |
Автор: brother79 20.4.2010, 11:24 | ||
Если у тебя документ корректный - то ты знаешь, какие теги должны иметь закрывающийся, а какие нет, например <br>, если же какой-то м.... пишет не закрытый <td> или ещё чего, ты на это универсальную прогу не придумаешь. Я бы предложил - нормальный код парсить или делать препроход и закрывать те же <td> перед <tr> |
Автор: Gold Dragon 20.4.2010, 11:55 |
я пишу модуль вывода краткого содержимого старей/новостей для CMS. И поэтому модуль будут использовать как угодно и где угодно... скорее всего нужно писать с простого и по мере новых версий вводить новые теги.. другого выхода пока не вижу. Пока будут получаться неоправданные затраты |
Автор: ksnk 20.4.2010, 12:18 |
Gold Dragon, Есть мысль - заставить юзера(юзеровый броузер) самого впилить все нужные теги... Новости - это кусочки откопипащеных html'ей? Тогда нужно просто вставить этот текст в какой-то фрейм в html документе, на клиентской стороне у самого "редактора", а потом брать с собой на сервер то, что броузер уже успел "открыть-закрыть". Просто у броузера уже есть механизм исправления корявого кода и им вполне можно пользоваться ![]() C кодом на сервере нужно, конечно, проделать много дополнительных телодвижений - stripTags для непонятных тегов, очистка понятных тегов от странного и лишнего форматирования и протчий клининг... |
Автор: SickFxck 21.4.2010, 21:08 | ||
Я до сих пор не вижу проблемы. В данном случае вы просто неправильно "откусили" вот и всё. "Кусать" надо до тех пор, пока не закроются все теги, попавшие в текст, длиной 150 символов. Да, строка может получиться длиннее 150-ти символов, но зато тут виден какой-то алгоритм. Ещё раз спрашиваю: какой алгоритм выбрал тредстартер? Добавлено через 3 минуты и 45 секунд Сложнее всего ответить на вопрос: «а что вообще такое «подстрока гипертекста»? Что вообще вы хотите увидеть, попытавшись получить «150 символов таблицы»? Я смысла в этом вообще вижу мало. |
Автор: smartov 21.4.2010, 21:39 | ||
Очень класно. Обрежем 150 символов, но не 150 символов. Соответствие решения техзаданию даже близко не валяется. А я вижу. Раз просят 150, надо сделать все, чтобы было максимально близко, а не делать как получится, потому что так удобнее |
Автор: SickFxck 21.4.2010, 21:50 | ||
smartov, ответь на вопросы:
А уже только потом можно будет поговорить о реализации. |
Автор: smartov 22.4.2010, 07:17 |
SickFxck, мне задание очевидно - его бизнес логика сродни тому, почему у нас на винграде при нажатии кнопки "быстрая цитата" скрипт вставляет цитируемый текст без форматирования, а должен бы с ним. Если у тебя еще есть вопросы - задавай их ТС, а не мне. |
Автор: SickFxck 22.4.2010, 07:51 | ||
То, что ты не можешь точно описать, не существует. Тогда просьба не оценивать чужие предложения на соответствие "техзаданию" автора: |
Автор: smartov 22.4.2010, 14:23 | ||
Согласен. Прошу прощения. Может автору действительно подходит твой алгоритм. |
Автор: Gold Dragon 27.4.2010, 07:57 | ||||||
Извините. был занят... Может я не совсем правильно всем объяснил... вот на примере есть примеры следующего контекста
Сам текст может иметь любые стили форматирования. И как видно, нужно не только закрывать теги, но и "научить" парсер в каком порядке их закрывать. И строка само собой получится более 150 символов.. Нужно сохранять 150 текста ![]() Добавлено через 2 минуты и 48 секунд интересный вариант предложил brother79, осталось понять логику как это реализовать |
Автор: SelenIT 27.4.2010, 09:59 |
Если в лоб, можно попробовать тупо вырезать без учета тегов (напр., регуляркой типа '/([^<>](<[^<>]*>)*){0,150}/s'), а на результат натравить какой-нибудь tidy_repair_string (пусть сам чинит покоцаную разметку;) и из результата вырезать всё между <body>...</body>. Возможно, как вариант, вместо Tidy - DOMDocument::loadHTML (не проверял, поэтому не уверен). Но вообще подход рискованный. Если это для новых статей/новостей, которые вводятся через WYSIWYG-редактор, лично я бы сделал как-нибудь так: для краткого содержания завел бы отдельное поле (тоже WYSIWYG'овое) и по достижении нужного лимита значением innerText.length/textContent.length основного поля копировал бы innerHTML основного поля туда яваскриптом, оставив редактору новости возможность вручную поменять его на что-то более осмысленное (напр., заменить обрезок таблицы на краткую аннотацию к ней). |
Автор: SickFxck 27.4.2010, 15:10 | ||
Через стек просто делается:
|
Автор: SelenIT 27.4.2010, 16:49 | ||||
Кстати,
справедливо для XML (включая XHTML как application/xhtml+xml), но не для HTML (включая XHTML как text/html). В HTML для пустых (принципиально не имеющих содержимого) тегов закрывающий тег именно что http://www.w3.org/TR/html4/index/elements.html. И <col> - как раз один из таких тегов;) По сабжу, в первом приближении работает и такое:
Закрывает всё вроде как надо (проверил на примерах из топика). Правда, нужна поддержка Tidy на сервере и кодировка utf-8 (с cp1251 у меня не получилось). И сбитые rowspan/colspan таблиц не лечит (в принципе, пустяк, таблица-то закрыта, вёрстка дальше не поплывёт)... |
Автор: Gold Dragon 28.4.2010, 07:29 |
что такое Tidy? |
Автор: Gold Dragon 28.4.2010, 08:15 | ||
SickFxck, твой код практически отлично работает.. не пробовал на таблицах, но с другими элементами вроде пащет.. Правда <IMG> не проверил... А так всё открывается и закрывается.. НО(!) - задаваемый размер не соответствует реальному тексту - не учтено всякие специальные символы типа « SickFxck, можешь пояснить что и как делается в коде? что-то я запутался ![]() вот для примера код
|
Автор: SickFxck 28.4.2010, 08:55 | ||
Скорее всего это одна и та же проблема. Вечером выложу исправленный вариант, если ничего другого не найдёшь. Добавлено через 53 секунды А если ты работаешь с UTF-8, то там нужно mb-функции использовать. |
Автор: Gold Dragon 28.4.2010, 08:58 |
SickFxck, прокомментируй код.. Хочу разобраться ![]() |
Автор: SelenIT 28.4.2010, 11:39 | ||
Фактически http://php.net/tidy. У меня учтено;)
|
Автор: SickFxck 28.4.2010, 13:06 | ||
|
Автор: SickFxck 28.4.2010, 14:40 | ||
Если кратко, то, встречая открывающий тег (парный), мы его пихаем в стек, если встретился закрывающий — выталкиваем. Если длина строки превысила допустимое количество — прерываем цикл. После выталкиваем все незакрытые теги. Я пользуюсь тем, что preg_split($pattern, $subject, -1, PREG_SPLIT_DELIM_CAPTURE) возвращает массив в виде чередующихся строк и подстрок, подходящих под шаблон. То есть, тег всегда будет в нечётных индексах массива, а простой текст — в чётных. Да и ещё один фикс:
P.S. И заметь, что, например, "&" я считаю одним символом ("&"), а не 5-ю. |
Автор: Gold Dragon 29.4.2010, 07:39 |
боюсь что Tidy не могу использовать. не на всех серверах он установлен. Проверил у своих хостеров, только у одного стоит :( |
Автор: Gold Dragon 29.4.2010, 10:37 |
никак не пойму почему количество заданных символов не соответствует реальной обрезке :( и разница колеблется в случайном порядке, как в большую сторону так и в меньшую |
Автор: SickFxck 29.4.2010, 11:18 | ||||||||
Ты про чей вариант? Свой я уже пояснил:
Поэтому нельзя делать проверку с помощью strlen(). Ах да. Действительно есть кое-что. Окончательный вариант:
|
Автор: Gold Dragon 29.4.2010, 11:52 |
теперь код отлично работает на этом этапе ![]() если есть <img...> а не <img ... /> то появится </img> ![]() а можно как то включить в условия чтобы если встретится например тег <myqqq> то просто его игнорировать и оставить в коде? |
Автор: SickFxck 29.4.2010, 11:58 | ||||
Делай массив таких тегов
Добавь условие здесь:
substr(), strtok(), strtolower(), in_array()... |
Автор: SelenIT 29.4.2010, 13:55 |
Я думаю, адекватного хостера можно попросить его добавить. Всё-таки стандартные решения надежнее, имхо (хотя бы тем, что не надо самому заводить массивы пустых тегов и разрешенных тегов)... |
Автор: Gold Dragon 29.4.2010, 15:38 |
SelenIT, согласен с тобой.. Но не всё так просто ... ни каждый хостер будет доставлять библиотеки по желанию пользователей... хотя я думаю нужно и этот вариант сделать, а в настройках давать пользователю вариант выбирать... |