修改
我最终使用了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));
我该如何解决?我会开一个赏金,因为原来的问题已经回答了......
答案 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 截断为截断的字符串。是的,必须考虑标点符号。
更多规则将创建一个合适的逻辑来确定句子的结尾。