【问题标题】:Truncate html text while taking in consideration "full stops" (in CachePHP TextHelper->truncate)在考虑“句号”的同时截断 html 文本(在 CachePHP TextHelper->truncate 中)
【发布时间】:2011-09-15 22:38:17
【问题描述】:

编辑:

我最终使用了 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));

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

【问题讨论】:

  • 我想你刚刚回答了你的问题。因此,您可以继续添加新单词,直到找到“。”。并从计算文本中减去单词,直到找到“。”然后比较长度并选择好的长度。完成此操作后,尝试优化:)
  • 嘿!我想我确实回答了你原来的问题,但我很高兴你找到了解决方案!我正在查看 Rails 的 truncate 方法的源代码,它提供的功能与您正在寻找的功能非常相似。
  • 谢谢 Alex,你能发个 Rails 函数的链接吗?
  • 当然可以在the docs找到。您可以传递一个:separator 参数(您可以将其设置为一个句点),它会在自然中断处截断文本。
  • 老实说,次要问题应该完全是另一个问题。但是,既然你已经在这里放了一个赏金,我们不妨试一试:)

标签: php arrays string cakephp truncate


【解决方案1】:

This snippet 解决了您要查找的问题,并列出了它的失败(句号可能不表示句子结束,而其他标点符号可以结束句子)。

它会扫描最多$maxLen 的字符,然后在它找到的最后一个句号之后有效地“丢弃”一个部分句子。

在你的情况下,你会在返回 $new_text 之前使用这个函数。

【讨论】:

    【解决方案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() 相比。

    【讨论】:

    • 上面的正则表达式可能有效。但是,考虑到效率,在这种情况下,我们可能会先将字符串截断为 max_length,然后对截断的字符串进行 preg。是的,必须考虑标点符号。
    • @acpmasquerade - 目的是在truncate() 之后 运行正则表达式,以便在最大字符限制之前找到最早可能的句尾。事先使用正则表达式是没有意义的,因为在将字符串截断为长度时结果会丢失。
    【解决方案3】:

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

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

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

    1. 标点符号后的空格或 EOL
    2. 所选标点符号后的第一个单词,大写。
    3. 在标点符号等之后多换行(段落结尾)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-05
      • 2021-11-13
      • 1970-01-01
      • 2021-04-14
      • 1970-01-01
      • 2016-05-08
      • 2017-06-22
      相关资源
      最近更新 更多