如何将PHP中的字符串截断为最接近一定数量字符的单词?

Bri*_*ian 177 php string function

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

Gre*_*her 217

通过使用wordwrap功能.它将文本分成多行,使得最大宽度是您指定的宽度,在字边界处断开.拆分后,您只需占用第一行:

substr($string, 0, strpos(wordwrap($string, $your_desired_width), "\n"));
Run Code Online (Sandbox Code Playgroud)

这个oneliner无法处理的一件事是文本本身短于所需宽度的情况.要处理这种边缘情况,应该做以下事情:

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

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

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));
}
Run Code Online (Sandbox Code Playgroud)

此外,这里是用于测试实现的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));
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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

  • 使用 UTF-8 时请小心使用 `mb_substr` 而不是 `substr` (2认同)

mat*_*mac 136

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

preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, 201));
Run Code Online (Sandbox Code Playgroud)

  • 只需将其包装在一个检查中,以确保字符串比您测试的更长(与接受的答案相同)`if(strlen($ string)> $ your_desired_width){preg_replace(...); }` (24认同)
  • 几乎.无论怎样,似乎它为我删除了句子的最后一个字. (7认同)
  • 对正则表达式的微小改进:括号使最终的 \S+ 对匹配而言是可选的,但它们也捕获了这些字符。由于我们不需要捕获这些字符,因此可以像这样使括号不被捕获:`/\s+?(?:\S+)?$/` (2认同)

小智 45

$WidgetText = substr($string, 0, strrpos(substr($string, 0, 200), ' '));
Run Code Online (Sandbox Code Playgroud)

而且你有它 - 一种可靠的方法,可以将任何字符串截断为最接近的整个单词,同时保持在最大字符串长度之下.

我尝试过上面的其他例子,但没有产生预期的结果.

  • 如果给定字符串的长度小于最大长度,则会切断所有内容,直到最后一个空格.为避免这种情况,请将其包含在`if`语句中:`if(strlen($ str)> 200){...}` (11认同)
  • 一个问题是如果字符串不包含空格,它会返回一个空字符串。 (2认同)

Ser*_*nko 36

当我注意到wordwrap函数的$ break参数时,出现了以下解决方案:

string wordwrap(string $ str [,int $ width = 75 [,string $ 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");
}
Run Code Online (Sandbox Code Playgroud)

示例#1.

print truncate("This is very long string with many chars.", 25);
Run Code Online (Sandbox Code Playgroud)

上面的例子将输出:

This is very long string...
Run Code Online (Sandbox Code Playgroud)

例#2.

print truncate("This is short string.", 25);
Run Code Online (Sandbox Code Playgroud)

上面的例子将输出:

This is short string.
Run Code Online (Sandbox Code Playgroud)

  • 如果字符串已经有一个新行字符(例如,如果你试图提取博客文章的`描述),这不起作用) (2认同)

Gar*_*ght 9

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

对于非ASCII字符,还有一个需要注意的事情; 包含它们的字符串可能被PHP的标准strlen()解释为比它们实际上更长,因为单个字符可能需要两个或更多字节而不是一个字节.如果你只是使用strlen()/ substr()函数来分割字符串,你可以在字符的中间分割一个字符串!如果有疑问,mb_strlen()/mb_substr()更加万无一失.


Luc*_*man 8

使用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;
Run Code Online (Sandbox Code Playgroud)

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


Unk*_*ech 7

干得好:

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;
   }
}
Run Code Online (Sandbox Code Playgroud)


Cam*_*oft 5

这是我的功能基于@ Cd-MaN的方法.

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

  return $string;
}
Run Code Online (Sandbox Code Playgroud)


hlc*_*lcs 5

$shorttext = preg_replace('/^([\s\S]{1,200})[\s]+?[\s\S]+/', '$1', $fulltext);
Run Code Online (Sandbox Code Playgroud)

描述:

  • ^ - 从字符串的开头开始
  • ([\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排除。

享受。