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

有帮助吗?

解决方案

通过使用 自动换行 功能。它将文本分成多行,使最大宽度为您指定的宽度,并在字边界处断开。分割后,只需取第一行:

substr($string, 0, strpos(wordwrap($string, $your_desired_width), "\n"));

此 oneliner 无法处理的一件事是文本本身比所需宽度短的情况。要处理这种边缘情况,应该执行以下操作:

if (strlen($string) > $your_desired_width) 
{
    $string = wordwrap($string, $your_desired_width);
    $string = substr($string, 0, strpos($string, "\n"));
}

上述解决方案存在如果文本在实际剪切点之前包含换行符则过早剪切文本的问题。这是解决这个问题的版本:

function tokenTruncate($string, $your_desired_width) {
  $parts = preg_split('/([\s\n\r]+)/', $string, null, PREG_SPLIT_DELIM_CAPTURE);
  $parts_count = count($parts);

  $length = 0;
  $last_part = 0;
  for (; $last_part < $parts_count; ++$last_part) {
    $length += strlen($parts[$last_part]);
    if ($length > $your_desired_width) { break; }
  }

  return implode(array_slice($parts, 0, $last_part));
}

另外,这里是用于测试实现的 PHPUnit 测试类:

class TokenTruncateTest extends PHPUnit_Framework_TestCase {
  public function testBasic() {
    $this->assertEquals("1 3 5 7 9 ",
      tokenTruncate("1 3 5 7 9 11 14", 10));
  }

  public function testEmptyString() {
    $this->assertEquals("",
      tokenTruncate("", 10));
  }

  public function testShortString() {
    $this->assertEquals("1 3",
      tokenTruncate("1 3", 10));
  }

  public function testStringTooLong() {
    $this->assertEquals("",
      tokenTruncate("toooooooooooolooooong", 10));
  }

  public function testContainingNewline() {
    $this->assertEquals("1 3\n5 7 9 ",
      tokenTruncate("1 3\n5 7 9 11 14", 10));
  }
}

编辑 :

不处理像“à”这样的特殊 UTF8 字符。在 REGEX 末尾添加 'u' 来处理它:

$parts = preg_split('/([\s\n\r]+)/u', $string, null, PREG_SPLIT_DELIM_CAPTURE);

其他提示

这将返回单词的前 200 个字符:

preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, 201));
$WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' '));

现在你已经有了它——一种可靠的方法,可以将任何字符串截断为最接近的整个单词,同时保持在最大字符串长度以下。

我已经尝试了上面的其他示例,但它们没有产生预期的结果。

当我注意到 $break 参数时,以下解决方案诞生了 自动换行 功能:

字符串wordwrap(字符串$ str [,int $ width = 75 [,字符串$ break =“ n” [,bool $ cut = false]]])

这是 解决方案:

/**
 * Truncates the given string at the specified length.
 *
 * @param string $str The input string.
 * @param int $width The number of chars at which the string will be truncated.
 * @return string
 */
function truncate($str, $width) {
    return strtok(wordwrap($str, $width, "...\n"), "\n");
}

例子#1。

print truncate("This is very long string with many chars.", 25);

上面的例子将输出:

This is very long string...

例子#2。

print truncate("This is short string.", 25);

上面的例子将输出:

This is short string.

请记住,每当您在任何地方用“单词”分割时,某些语言(例如中文和日语)不使用空格字符来分割单词。此外,恶意用户可以简单地输入不带任何空格的文本,或者使用一些类似于标准空格字符的 Unicode,在这种情况下,您使用的任何解决方案最终都可能显示整个文本。解决这个问题的一种方法可能是在正常地将字符串拆分为空格后检查字符串长度,然后,如果字符串仍然高于异常限制(在本例中可能是 225 个字符),则继续并在该限制下愚蠢地拆分它。

当涉及到非 ASCII 字符时,还有一个关于此类问题的警告;包含它们的字符串可能会被 PHP 的标准 strlen() 解释为比实际长度长,因为单个字符可能需要两个或更多字节,而不是一个字节。如果你只是使用strlen()/substr()函数来分割字符串,你可能会在一个字符的中间分割一个字符串!有疑问时, mb_strlen()/mb_substr() 更加万无一失。

使用 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 个字符后的第一个空格处被截断的字符串。

这是我基于@Cd-MaN 方法的函数。

function shorten($string, $width) {
  if(strlen($string) > $width) {
    $string = wordwrap($string, $width);
    $string = substr($string, 0, strpos($string, "\n"));
  }

  return $string;
}

干得好:

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

令人惊讶的是,找到这个问题的完美解决方案是多么棘手。我还没有在此页面上找到至少在某些情况下不会失败的答案(特别是如果字符串包含换行符或制表符,或者分词符不是空格,或者字符串包含 UTF- 8 个多字节字符)。

这是一个适用于所有情况的简单解决方案。这里有类似的答案,但是如果您希望它能够处理多行输入,则“s”修饰符很重要,并且“u”修饰符使其可以正确评估 UTF-8 多字节字符。

function wholeWordTruncate($s, $characterCount) 
{
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) return $match[0];
    return $s;
}

一种可能的边缘情况......如果字符串的前 $characterCount 个字符中根本没有任何空格,则它将返回整个字符串。如果您希望它在 $characterCount 处强制中断,即使它不是单词边界,您也可以使用以下命令:

function wholeWordTruncate($s, $characterCount) 
{
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) return $match[0];
    return mb_substr($return, 0, $characterCount);
}

最后一个选项,如果你想让它在截断字符串时添加省略号......

function wholeWordTruncate($s, $characterCount, $addEllipsis = ' …') 
{
    $return = $s;
    if (preg_match("/^.{1,$characterCount}\b/su", $s, $match)) 
        $return = $match[0];
    else
        $return = mb_substr($return, 0, $characterCount);
    if (strlen($s) > strlen($return)) $return .= $addEllipsis;
    return $return;
}
$shorttext = preg_replace('/^([\s\S]{1,200})[\s]+?[\s\S]+/', '$1', $fulltext);

描述:

  • ^ - 从字符串的开头开始
  • ([\s\S]{1,200}) - 获取 1 到 200 个任意字符
  • [\s]+? - 短文本末尾不包含空格,这样我们就可以避免 word ... 代替 word...
  • [\s\S]+ - 匹配所有其他内容

测试:

  1. regex101.com 让我们添加到 or 其他几个 r
  2. regex101.com orrrr 正好 200 个字符。
  3. regex101.com 第五次之后 r orrrrr 排除。

享受。

我将使用 preg_match 函数来执行此操作,因为您想要的是一个非常简单的表达式。

$matches = array();
$result = preg_match("/^(.{1,199})[\s]/i", $text, $matches);

该表达式意味着“从长度1-200开始以空间结尾的长度开始匹配的任何子弦”。结果是$结果,匹配项为$匹配。这解决了您原来的问题,该问题特别以任何空格结尾。如果你想让它以换行符结束,请将正则表达式更改为:

$result = preg_match("/^(.{1,199})[\n]/i", $text, $matches);

好吧,我根据上面的答案得到了另一个版本,但考虑了更多的事情(utf-8、 和 &nbsp ;),如果与 wp 一起使用,还有一行剥离 wordpress 短代码注释。

function neatest_trim($content, $chars) 
  if (strlen($content) > $chars) 
  {
    $content = str_replace('&nbsp;', ' ', $content);
    $content = str_replace("\n", '', $content);
    // use with wordpress    
    //$content = strip_tags(strip_shortcodes(trim($content)));
    $content = strip_tags(trim($content));
    $content = preg_replace('/\s+?(\S+)?$/', '', mb_substr($content, 0, $chars));

    $content = trim($content) . '...';
    return $content;
  }
/*
Cut the string without breaking any words, UTF-8 aware 
* param string $str The text string to split
* param integer $start The start position, defaults to 0
* param integer $words The number of words to extract, defaults to 15
*/
function wordCutString($str, $start = 0, $words = 15 ) {
    $arr = preg_split("/[\s]+/",  $str, $words+1);
    $arr = array_slice($arr, $start, $words);
    return join(' ', $arr);
}

用法:

$input = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna liqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.';
echo wordCutString($input, 0, 10); 

这将输出前 10 个单词。

preg_split 函数用于将字符串拆分为子字符串。字符串分割的边界是使用正则表达式模式指定的。

preg_split 函数有 4 个参数,但现在只有前 3 个与我们相关。

第一个参数 - 模式第一个参数是沿着字符串分开的正则表达式模式。在我们的例子中,我们希望跨单词边界分割字符串。因此我们使用预定义的字符类 \s 它匹配空白字符,例如空格、制表符、回车符和换行符。

第二个参数 - 输入字符串第二个参数是我们要拆分的长文本字符串。

第三参数 - 限制第三个参数指定应返回的子字符串的数量。如果您将限制设置为 n, preg_split 将返回一个包含 n 个元素的数组。首先 n-1 元素将包含子字符串。最后 (n th) 元素将包含字符串的其余部分。

基于@Justin Poliey 的正则表达式:

// Trim very long text to 120 characters. Add an ellipsis if the text is trimmed.
if(strlen($very_long_text) > 120) {
  $matches = array();
  preg_match("/^(.{1,120})[\s]/i", $very_long_text, $matches);
  $trimmed_text = $matches[0]. '...';
}

这是对 mattmac 答案的一个小修复:

preg_replace('/\s+?(\S+)?$/', '', substr($string . ' ', 0, 201));

唯一的区别是在 $string 末尾添加一个空格。这可确保最后一个单词不会按照 ReX357 的注释被截断。

我没有足够的代表点来添加此评论。

我有一个函数几乎可以满足您的需求,如果您进行一些编辑,它将完全适合:

<?php
function stripByWords($string,$length,$delimiter = '<br>') {
    $words_array = explode(" ",$string);
    $strlen = 0;
    $return = '';
    foreach($words_array as $word) {
        $strlen += mb_strlen($word,'utf8');
        $return .= $word." ";
        if($strlen >= $length) {
            $strlen = 0;
            $return .= $delimiter;
        }
    }
    return $return;
}
?>

我就是这样做的:

$string = "I appreciate your service & idea to provide the branded toys at a fair rent price. This is really a wonderful to watch the kid not just playing with variety of toys but learning faster compare to the other kids who are not using the BooksandBeyond service. We wish you all the best";

print_r(substr($string, 0, strpos(wordwrap($string, 250), "\n")));

我知道这已经很旧了,但是...

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

我以前用过这个

<?php
    $your_desired_width = 200;
    $string = $var->content;
    if (strlen($string) > $your_desired_width) {
        $string = wordwrap($string, $your_desired_width);
        $string = substr($string, 0, strpos($string, "\n")) . " More...";
    }
    echo $string;
?>

我创建了一个更类似于 substr 的函数,并使用@Dave 的想法。

function substr_full_word($str, $start, $end){
    $pos_ini = ($start == 0) ? $start : stripos(substr($str, $start, $end), ' ') + $start;
    if(strlen($str) > $end){ $pos_end = strrpos(substr($str, 0, ($end + 1)), ' '); } // IF STRING SIZE IS LESSER THAN END
    if(empty($pos_end)){ $pos_end = $end; } // FALLBACK
    return substr($str, $pos_ini, $pos_end);
}

附:全长切割可能小于子长度。

将 IF/ELSEIF 语句添加到代码中 戴夫阿迈勒穆拉里 用于处理没有空格的字符串

if ((strpos($string, ' ') !== false) && (strlen($string) > 200)) { 
    $WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' ')); 
} 
elseif (strlen($string) > 200) {
    $WidgetText = substr($string, 0, 200);
}

我相信这是最简单的方法:

$lines = explode('♦♣♠',wordwrap($string, $length, '♦♣♠'));
$newstring = $lines[0] . ' &bull; &bull; &bull;';

我使用特殊字符来分割文本并剪切它。

我发现这有效:

函数 abbreviate_string_to_whole_word($string,$max_length,$buffer) {

if (strlen($string)>$max_length) {
    $string_cropped=substr($string,0,$max_length-$buffer);
    $last_space=strrpos($string_cropped, " ");
    if ($last_space>0) {
        $string_cropped=substr($string_cropped,0,$last_space);
    }
    $abbreviated_string=$string_cropped."&nbsp;...";
}
else {
    $abbreviated_string=$string;
}

return $abbreviated_string;

}

缓冲区允许您调整返回字符串的长度。

用这个:

以下代码将删除 ','。如果您有任何其他字符或子字符串,您可以使用它来代替“,”

substr($string, 0, strrpos(substr($string, 0, $comparingLength), ','))

// 如果你有另一个字符串帐户

substr($string, 0, strrpos(substr($string, 0, $comparingLength-strlen($currentString)), ','))

在这里你可以尝试这个

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

也许这会对某人有所帮助:

<?php

    $string = "Your line of text";
    $spl = preg_match("/([, \.\d\-''\"\"_()]*\w+[, \.\d\-''\"\"_()]*){50}/", $string, $matches);
    if (isset($matches[0])) {
        $matches[0] .= "...";
        echo "<br />" . $matches[0];
    } else {
        echo "<br />" . $string;
    }

?>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top