Головоломка: правильное разбиение строки HTML - PullRequest
5 голосов
/ 01 августа 2010

Я пытаюсь разделить строку HTML по токену, чтобы создать предварительный просмотр блога без отображения полной записи. Это немного на 1001 сложнее, чем я думал. Вот проблемы:

  • Пользователь будет создавать HTML через редактор WYSIWYG (CKEditor). Разметка не гарантируется симпатичный или последовательный.
  • Жетон, read_more(), банка быть размещены в любом месте строки, в том числе будучи вложенным в тег абзаца.
  • Результирующая первая строка разбиения должен быть действительный HTML для всех разумное использование токена.

Примеры возможного использования:

<p>Some text here. read_more()</p>

<p>Some text read more() here.</p>

<p>read_more()</p>

<p>  read_more()</p>

read_more()

До сих пор я пытался просто разбить строку на токене, но он оставляет недействительный HTML. Regex, возможно, еще один вариант. Какую стратегию вы бы использовали, чтобы решить эту проблему и сделать ее максимально пуленепробиваемой? Любые фрагменты кода или подсказки также приветствуются (я использую PHP).

Ответы [ 6 ]

2 голосов
/ 01 августа 2010
function stripmore($in)
{
    list($p1,$p2) = explode("read_more()",$in,2);

    $pass1 = preg_replace("~>[^<>]+<~","><",$p2);
    $pass2 = preg_replace("~^[^<>]+~","",$pass1);

    $pass3 = null;
    while ( $pass3 != $pass2 )
    {
        if ( $pass3 !== null ) $pass2 = $pass3;
        $pass3 = preg_replace("~<([^<>]+)></\\1>~","",$pass2);
    }

    return $p1."read_more()".$pass3;
}

это удаляет любой не-html после метки read_more () и уменьшает его до минимума, удаляя соответствующие теги, сохраняя любой тег, начинающийся до и заканчивающийся после метки:

<p>Some text here. read_more()</p>
      ==> <p>Some text here. read_more()</p>

<p>Some <b>text</b> read_more() <b>here</b>.</p>
      ==> <p>Some <b>text</b> read_more()</p>

<p>Some <b>text read_more() here</b>.</p>
      ==> <p>Some <b>text read_more()</b></p>
1 голос
/ 09 февраля 2011

PHP tidy - очень легкая и эффективная утилита для исправления недействительных тегов. Посмотрите, я использовал его и протестировал в своем приложении, и он прекрасно работает. Более того, он имеет множество параметров конфигурации, чтобы удовлетворить ваши потребности наилучшим образом, и заботится о других возможных проблемах, таких как кодирование, вложенные недействительные теги и т. Д.

см. Ссылку: http://www.php.net/manual/en/tidy.cleanrepair.php

пример использования:

<?php

    function tidyString($str)
    {
      $config = array('show-body-only' => true); /* else it adds HTML tags too */
      tidy_set_encoding('utf8');
      $outStr = tidy_repair_string($str,$config);
      return $outStr;
    }


    $inStr = "<span> this is my incorrect html</spa";
    echo tidyString($inStr);  // Output : <span>this is my incorrect html</span>

    ?>
1 голос
/ 01 августа 2010

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

Почему вы не можете просто использовать trim () для получающегося в результатестроку, найдите отсутствующий элемент open или close и добавьте его соответствующим образом, чтобы сделать его действительным HTML?

Просто пройдите вперед и назад, чтобы найти следующий элемент открытия / закрытия, и исправьте свой HTML.

Итак, вы можете просто идти вперед и назад в строке, чтобы получить следующие < и >, и, если это HTML-элемент, остановитесь на этом, в противном случае продолжайте.

В идеале вам нужно обрабатывать это один раз для каждого представления, поэтому вы продолжаете платить цену за эту операцию.

ОБНОВЛЕНИЕ:

Я забыл добавить ссылку напомочь с strpos:

http://tuxradar.com/practicalphp/4/7/5

1 голос
/ 01 августа 2010

Вместо использования полного HTML, почему бы не использовать один из многих языков разметки, которые могут генерировать HTML, но которые не требуют, чтобы вы закрывали теги и т. Д. Было бы проще обучить ваших пользователей и избежать всех возможности для атак XSS, которые допускает необработанный HTML.

PHP Markdown может показаться очевидным, особенно в свете вашего желания избегать GNU GPL.

1 голос
/ 01 августа 2010

Единственный правильный вариант, который я сейчас вижу, - это написание собственного PHP-анализатора грамматики без контекста в PHP, который позволит вам соответствующим образом закрывать теги (просто выталкивая стек при достижении read more () и для каждого всплывающего окна добавляя закрытиетег).Это, однако, большая работа, и она может хорошо сработать для вас:

$stripped = strip_tags($input);
list($preview) = explode("read more()", $stripped);

Вы потеряете разметку HTML, но ее очень легко реализовать.И нет XSS на вашей главной странице:)

0 голосов
/ 01 августа 2010

Почему бы не использовать две текстовые области?Один выше и ниже разреза?Это должно сделать для пользователя очевидным, что происходит, и устранить головную боль для вас.

Если вы делаете хотите использовать токен, вы должны выбрать что-то более отличительное.Может быть: <!--full body cut-->, который вы можете быть более уверенным, на самом деле контент не принимается за токен.

В любом случае, если вы хотите разбить строку на токене, вам просто нужно выяснить, где ваштокен равен с использованием strpos(), а затем с помощью substr() отрубите первую часть.Что-то вроде:

$intro = substr($text, 0, strpos($string, $token));

После этого запустите ваш $intro через tidy (расширение PHP) до , очистите синтаксис и затем удалите лишнюю хреньэто добавляет там.(Я думаю, что вы можете str_replace () дополнений с пустой строкой.)

...