拼图:正确拆分HTML字符串

时间:2010-08-01 01:26:11

标签: php regex string html-parsing

我正在尝试通过令牌拆分HTML字符串,以便在不显示完整帖子的情况下创建博客预览。它比我最初想的还要更难。以下是问题:

  • 用户将创建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。正则表达式可能是另一种选择。您将采用什么策略来解决这个问题并使其尽可能防弹?任何代码片段或提示也将受到赞赏(我正在使用PHP)。

6 个答案:

答案 0 :(得分:2)

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;
}

这会在read_more()标记之后删除任何非html,并通过剥离相应的标记将其减少到最小值,同时保持任何标记在标记之前和结束之后开始:

<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 :(得分:1)

我目前看到的唯一正确选项是在PHP中编写自己的无上下文语法HTML解析器,这将允许您适当地关闭标记(只需通过在读取更多()时弹出堆栈,并为每个pop添加关闭标签)。

然而,这是很多工作,这可能适合你:

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

您丢失了HTML标记,但它很容易实现。首页上没有可能的XSS:)

答案 2 :(得分:1)

为什么不使用可以生成HTML的许多标记语言中的一种,而不是要求您关闭标记等,而不是使用完整的HTML。这将更容易培训您的用户,并将避免所有接受原始HTML的XSS攻击的可能性允许。

PHP Markdown似乎显然是合适的,特别是考虑到你想要避免使用GNU GPL。

答案 3 :(得分:1)

为了回答对我的评论的评论,我决定让它成为一个答案,所以我可以利用标记选项。

为什么你不能在结果字符串上使用trim(),找到缺少的open或close元素并适当追加,以使其成为有效的HTML?

只需前后移动即可查找下一个打开/关闭元素,并修复HTML。

所以,你可以在字符串中向前和向后走,以获得下一个<>,如果这是一个HTML元素,那么就停在那里,否则继续前进。

理想情况下,每次提交都需要处理一次,因此您需要为此操作付出代价。

<强>更新

我忘了提供帮助strpos的链接:

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

答案 4 :(得分:1)

PHP整理是一个非常轻量级和高效的实用程序来修复无效标签。 看看,我已经使用过它并在我的应用程序中对它进行了基准测试,效果很好。 此外,它有许多配置选项,以满足您的需求,并处理其他可能的问题,如编码,嵌套无效标签等。

参见参考资料: 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>

    ?>

答案 5 :(得分:0)

为什么不使用两个textareas?一个在切割上方和下方?应该让用户明白发生了什么,并为您消除头痛。

如果你想要使用令牌,你应该选择更有特色的东西。也许:<!--full body cut-->你可以更确定一点,实际上并没有将内容误认为令牌。

无论如何,如果你想在令牌上拆分字符串,你只需要使用strpos()找出令牌 的位置,然后使用substr()来切断第一部分。类似的东西:

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

然后,将$introtidy(PHP扩展名)运行到clean up the syntax,然后剥去它添加的额外垃圾。 (我认为你可以使用空字符串str_replace()附加内容。)