我有一个用PHP编写的代码片段,它从数据库中提取一个文本块,并将其发送到网页上的一个小部件。原文可以是一篇很长的文章,也可以是一两个短句;但是对于这个小部件,我不能显示超过200个字符。我可以使用substr()在200个字符处切断文本,但结果将在单词中间切断——我真正想要的是在200个字符前的最后一个单词的末尾切断文本。


当前回答

虽然这是一个相当老的问题,但我想我可以提供一个替代方案,因为它没有被提到,而且对PHP 4.3+有效。

您可以使用sprintf系列函数来截断文本,方法是使用%。ℕs精密修改器。

句号。后面跟着一个整数,它的含义取决于 说明符: 对于e, e, f和f说明符:这是小数点后要打印的位数(默认情况下,这是6)。 对于g和g说明符:这是要打印的有效数字的最大数量。 对于说明符:它作为一个截断点,设置字符串的最大字符限制

简单截断https://3v4l.org/QJDJU

$string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var_dump(sprintf('%.10s', $string));

结果

string(10) "0123456789"

扩展截断https://3v4l.org/FCD21

因为sprintf的功能类似于substr,并且会部分切断单词。下面的方法将通过使用strpos(wordwrap(…, '[break]'), '[break]'),并使用特殊的分隔符。这允许我们检索位置,并确保我们不匹配标准的句子结构。

返回不部分截断单词且不超过指定宽度的字符串,同时保留换行符(如果需要)。

function truncate($string, $width, $on = '[break]') {
    if (strlen($string) > $width && false !== ($p = strpos(wordwrap($string, $width, $on), $on))) {
        $string = sprintf('%.'. $p . 's', $string);
    }
    return $string;
}
var_dump(truncate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', 20));

var_dump(truncate("Lorem Ipsum is simply dummy text of the printing and typesetting industry.", 20));

var_dump(truncate("Lorem Ipsum\nis simply dummy text of the printing and typesetting industry.", 20));

结果

/* 
string(36) "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"  
string(14) "Lorem Ipsum is" 
string(14) "Lorem Ipsum
is" 
*/

使用wordwrap($string, $width)或strtok(wordwrap($string, $width), "\n")的结果

/*
string(14) "Lorem Ipsum is"
string(11) "Lorem Ipsum"
*/

其他回答

给你:

function neat_trim($str, $n, $delim='…') {
   $len = strlen($str);
   if ($len > $n) {
       preg_match('/(.{' . $n . '}.*?)\b/', $str, $matches);
       return rtrim($matches[1]) . $delim;
   }
   else {
       return $str;
   }
}

你可以试试这个

substr( $str, 0, strpos($str, ' ', 200) ); 

使用strpos和substr:

<?php

$longString = "I have a code snippet written in PHP that pulls a block of text.";
$truncated = substr($longString,0,strpos($longString,' ',30));

echo $truncated;

这将为您提供一个在30个字符后的第一个空格处截断的字符串。

就我所知,这里所有的解只有在起点固定的情况下才有效。 允许你转动这个: 悲伤之神,神圣之神,痛苦之神,痛苦之神。Ut enim ad minim veniam。 到这个: 神圣的,神圣的… 如果想要截断一组特定关键字周围的单词,该怎么办?

截断一组特定关键字周围的文本。

我们的目标是能够转换这个:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna liqua. Ut enim ad minim veniam.

到这个:

...consectetur adipisicing elit, sed do eiusmod tempor...

这是在显示搜索结果、摘要等时非常常见的情况。为了实现这一点,我们可以结合使用以下两种方法:

    /**
     * Return the index of the $haystack matching $needle,
     * or NULL if there is no match.
     *
     * This function is case-insensitive  
     * 
     * @param string $needle
     * @param array $haystack
     * @return false|int
     */
    function regexFindInArray(string $needle, array $haystack): ?int
    {
        for ($i = 0; $i < count($haystack); $i++) {
            if (preg_match('/' . preg_quote($needle) . '/i', $haystack[$i]) === 1) {
                return $i;
            }
        }
        return null;
    }

    /**
     * If the keyword is not present, it returns the maximum number of full 
     * words that the max number of characters provided by $maxLength allow,
     * starting from the left.
     *
     * If the keyword is present, it adds words to both sides of the keyword
     * keeping a balanace between the length of the suffix and the prefix.
     *
     * @param string $text
     * @param string $keyword
     * @param int $maxLength
     * @param string $ellipsis
     * @return string
     */
    function truncateWordSurroundingsByLength(string $text, string $keyword, 
            int $maxLength, string $ellipsis): string
    {
        if (strlen($text) < $maxLength) {
            return $text;
        }

        $pattern = '/' . '^(.*?)\s' .
                   '([^\s]*' . preg_quote($keyword) . '[^\s]*)' .
                   '\s(.*)$' . '/i';
        preg_match($pattern, $text, $matches);

        // break everything into words except the matching keywords, 
        // which can contain spaces
        if (count($matches) == 4) {
            $words = preg_split("/\s+/", $matches[1], -1, PREG_SPLIT_NO_EMPTY);
            $words[] = $matches[2];
            $words = array_merge($words, 
                              preg_split("/\s+/", $matches[3], -1, PREG_SPLIT_NO_EMPTY));
        } else {
            $words = preg_split("/\s+/", $text, -1, PREG_SPLIT_NO_EMPTY);
        }

        // find the index of the matching word
        $firstMatchingWordIndex = regexFindInArray($keyword, $words) ?? 0;

        $length = false;
        $prefixLength = $suffixLength = 0;
        $prefixIndex = $firstMatchingWordIndex - 1;
        $suffixIndex = $firstMatchingWordIndex + 1;

        // Initialize the text with the matching word
        $text = $words[$firstMatchingWordIndex];

        while (($prefixIndex >= 0 or $suffixIndex <= count($words))
                and strlen($text) < $maxLength and strlen($text) !== $length) {
            $length = strlen($text);
            if (isset($words[$prefixIndex])
                and (strlen($text) + strlen($words[$prefixIndex]) <= $maxLength)
                and ($prefixLength <= $suffixLength 
                     or strlen($text) + strlen($words[$suffixIndex]) <= $maxLength)) {
                $prefixLength += strlen($words[$prefixIndex]);
                $text = $words[$prefixIndex] . ' ' . $text;
                $prefixIndex--;
            }
            if (isset($words[$suffixIndex])
                and (strlen($text) + strlen($words[$suffixIndex]) <= $maxLength)
                and ($suffixLength <= $prefixLength 
                     or strlen($text) + strlen($words[$prefixIndex]) <= $maxLength)) {
                $suffixLength += strlen($words[$suffixIndex]);
                $text = $text . ' ' . $words[$suffixIndex];
                $suffixIndex++;
            }
        }

        if ($prefixIndex > 0) {
            $text = $ellipsis . ' ' . $text;
        }
        if ($suffixIndex < count($words)) {
            $text = $text . ' ' . $ellipsis;
        }

        return $text;
    }

现在你可以做:

$text = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do' .
        'iusmod tempor incididunt ut labore et dolore magna liqua. Ut enim' .
        'ad minim veniam.';

$text = truncateWordSurroundingsByLength($text, 'elit', 25, '...');

var_dump($text); // string(32) "... adipisicing elit, sed do ..."

运行代码。

我知道这很旧,但是…

function _truncate($str, $limit) {
    if(strlen($str) < $limit)
        return $str;
    $uid = uniqid();
    return array_shift(explode($uid, wordwrap($str, $limit, $uid)));
}