在考虑“完全停止”时(在CachePHP TextHelper-> truncate中)截断html文本

时间:2011-09-15 22:38:17

标签: php arrays string cakephp truncate

修改

我最终使用了CakePHP的 truncate() 功能。它更快,支持unicode:D

但问题仍然存在:

如何使该功能自动检测完全停止(.)并在此之后切断它?因此基本上$length将被忽略。因此,如果新文本的句子不完整,则会在句子结束之前附加更多单词(或者删除,取决于从截止到下一个/上一个句子的字符串长度)

编辑2: 我发现了如何检测到完全停止。我换了:

 if (!$exact) {
   $spacepos = mb_strrpos($truncate, ' ');

 ...

 if (!$exact) {
    $spacepos = mb_strrpos($truncate, '.');
 ...

编辑 - 问题:

当我的标签如img在其属性中包含点时,文本会在标记内截止:

 $text = '<p>Abc def abc def abc def abc def. Abc def <img src="test.jpg" /></p><p>abc def abc def abc def abc def.</p>';

 echo htmlentities(truncate($text));

我该如何解决?我会开一个赏金,因为原来的问题已经回答了......

3 个答案:

答案 0 :(得分:5)

This snippet解决了你正在寻找的问题,并列出了它的失败(完全停止可能不表示句子结束,其他标点符号可以结束句子)。

它将扫描最多$maxLen的字符,然后在找到的最后一次完整停止后有效地“丢弃”部分句子。

在您的情况下,您只需在返回$new_text之前使用此功能。

答案 1 :(得分:2)

要解决“标记中的完整停止”问题,您可以使用类似于以下内容的方法来检测停止是否在标记内:

$str_len       = strlen($summary);
$pos_stop      = strrpos($summary, '.');
$pos_tag_open  = strrpos($summary, '<', -($str_len - $pos_stop));
$pos_tag_close = strpos($summary, '>', $pos_tag_open);

if (($pos_tag_open < $pos_stop) && ($pos_stop < $pos_tag_close)) {
  // Inside tag! Search for the next nearest prior full-stop.
  $pos_stop = strrpos($summary, '.', -($str_len - $pos_tag_open));
}

echo htmlentities(substr($summary, 0, $pos_stop + 1));

显然,这段代码可以进行优化(并将其拉出到自己的函数中),但是你明白了。我觉得有一个正则表达式可以更有效地处理这个问题。

修改

的确,正则表达式可以做到这一点,使用负向前瞻:

$text = '<p>Abc def abc def abc def abc def. Abc def <img src="test.jpg" />abc</p>';

$count = preg_match_all("/\.(?!([^<]+)?>)/", $text, $arr, PREG_OFFSET_CAPTURE);
$offset = $arr[0][$count-1][1];

echo substr($text, 0, $offset + 1)."\n";

这应该相对有效,至少与在内部使用preg_match的truncate()相比。

答案 2 :(得分:1)

Truncate html text while taking in consideration "full stops" (in CachePHP TextHelper->truncate)上方的正则表达式可能有效。

但是,考虑到效率,在这种情况下,我们可能首先将字符串截断为 max_length ,然后将 preg 截断为截断的字符串。是的,必须考虑标点符号。

更多规则将创建一个合适的逻辑来确定句子的结尾。

  1. 标点符号后面的空格或EOL
  2. 挑选标点后的第一个单词,有一个大写字母。
  3. 标点符号后面的多个新行(段落末尾)等。