views:

6629

answers:

8

I have a code snippet written in PHP that pulls a block of text from a database and sends it out to a widget on a webpage. The original block of text can be a lengthy article or a short sentence or two; but for this widget I can't display more than, say, 200 characters. I could use substr() to chop off the text at 200 chars, but the result would be cutting off in the middle of words-- what I really want is to chop the text at the end of the last word before 200 chars.

+12  A: 

By using the wordwrap function. It splits the texts in multiple lines such that the maximum width is the one you specified, breaking at word boundaries. After splitting, you simply take the first line:

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

One thing this oneliner doesn't handle is the case when the text itself is shorter than the desired width. To handle this edge-case, one should do something like:

if (strlen($string) <= $your_desired_width) {
    $string = $string; //do nothing
}
else {
    $string = wordwrap($string, $your_desired_width);
    $string = substr($string, 0, strpos($string, "\n"));
}
Cd-MaN
+3  A: 

Use strpos and substr:

$truncated = substr($longString,0,strpos($longString,' ',200)-1);

This will give you a string truncated at the first space after 200 characters.

Lucas Oman
+1  A: 

Here you go:

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;
   }
}
Unkwntech
+1  A: 

I would use the preg_match function to do this, as what you want is a pretty simple expression.

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

The expression means "match any substring starting from the beginning of length 1-200 that ends with a space." The result is in $result, and the match is in $matches. That takes care of your original question, which is specifically ending on any space. If you want to make it end on newlines, change the regular expression to:

$result = preg_match("/^(.{1,199})[\n]/i", $text, $matches);
Justin Poliey
+4  A: 

This will return the first 200 characters of words:

preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, 201));
mattmac
This actually works better than the accepted solution :)
Karan
Yeah it does! Thanks for this answer
tarnfeld
+2  A: 

Keep in mind whenever you're splitting by "word" anywhere that some languages such as Chinese and Japanese do not use a space character to split words. Also, a malicious user could simply enter text without any spaces, or using some Unicode look-alike to the standard space character, in which case any solution you use may end up displaying the entire text anyway. A way around this may be to check the string length after splitting it on spaces as normal, then, if the string is still above an abnormal limit - maybe 225 characters in this case - going ahead and splitting it dumbly at that limit.

One more caveat with things like this when it comes to non-ASCII characters; strings containing them may be interpreted by PHP's standard strlen() as being longer than they really are, because characters may take up two bytes of data instead of just one. When in doubt, mb_strlen() is a little more foolproof.

Garrett Albright
+1  A: 

Here is my function based on @Cd-MaN's approach.

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

  return $string;
}
Camsoft
A: 

Pretty obvious, but anyways, to the end you can add:

$long_string_already_truncated .= '...';

That way you add the '...' to the end of the last word.

PaBLoX