71

How can I truncate a string after 20 words in PHP?

1

29 Answers 29

151
function limit_text($text, $limit) {
    if (str_word_count($text, 0) > $limit) {
        $words = str_word_count($text, 2);
        $pos   = array_keys($words);
        $text  = substr($text, 0, $pos[$limit]) . '...';
    }
    return $text;
}

echo limit_text('Hello here is a long sentence that will be truncated by the', 5);

Outputs:

Hello here is a long ...
7
  • 6
    This function confuses character count and word count when using $limit in one case as a word selector of the array $pos and in another by determining if the string is long enough.
    – Aaron
    Commented Jul 6, 2010 at 19:21
  • In the example provided, passing in a value of 5 ensures that the function will act on any word of length greater than 5 characters, so had the test case been "Hello here", the function fails and returns only "..."
    – Aaron
    Commented Jul 6, 2010 at 19:42
  • 2
    str_word_count instead of strlen should do the trick :) so replace strlen($text) with str_word_count($text,0)
    – Val
    Commented Feb 21, 2012 at 15:26
  • 1
    Note on str_word_count($text, 2) from the docs For the purpose of this function, 'word' is defined as a locale dependent string containing alphabetic characters, which also may contain, but not start with "'" and "-" characters. you can specify additional characters in the third param, or just use preg_split('/[\s]+/' $text); to split by white space. Commented Sep 23, 2013 at 21:19
  • 1
    its working for english, not for Arabic language, i assume not for UTF-8? or am i missing something? Commented Jun 26, 2018 at 14:43
35

Change the number 3 to the number 20 below to get the first 20 words, or pass it as parameter. The following demonstrates how to get the first 3 words: (so change the 3 to 20 to change the default value):

function first3words($s, $limit=3) {
    return preg_replace('/((\w+\W*){'.($limit-1).'}(\w+))(.*)/', '${1}', $s);   
}

var_dump(first3words("hello yes, world wah ha ha"));  # => "hello yes, world"
var_dump(first3words("hello yes,world wah ha ha"));   # => "hello yes,world"
var_dump(first3words("hello yes world wah ha ha"));   # => "hello yes world"
var_dump(first3words("hello yes world"));  # => "hello yes world"
var_dump(first3words("hello yes world.")); # => "hello yes world"
var_dump(first3words("hello yes"));  # => "hello yes"
var_dump(first3words("hello"));  # => "hello"
var_dump(first3words("a")); # => "a"
var_dump(first3words(""));  # => ""
3
  • 2
    Amazing this is fastest way so far for word limiting, this performs slighty better than explode, great job, well done.
    – VeeeneX
    Commented Jul 1, 2015 at 4:58
  • 2
    Just a side note: If theres line breaks inside your string, this function will truncade every 20 words for every sentence (assuming you have a line break after every sentence).
    – user10736793
    Commented Apr 10, 2019 at 0:21
  • To match across lines ((\w+[\W|\s]*){'.($limit-1).'}\w+|\W|\s)(?:(.*|\s)) will need trim after for the trailing line breaks Commented Nov 1, 2021 at 12:25
14

To Nearest Space

Truncates to nearest preceding space of target character. Demo

  • $str The string to be truncated
  • $chars The amount of characters to be stripped, can be overridden by $to_space
  • $to_space boolean for whether or not to truncate from space near $chars limit

Function

function truncateString($str, $chars, $to_space, $replacement="...") {
   if($chars > strlen($str)) return $str;

   $str = substr($str, 0, $chars);
   $space_pos = strrpos($str, " ");
   if($to_space && $space_pos >= 0) 
       $str = substr($str, 0, strrpos($str, " "));

   return($str . $replacement);
}

Sample

<?php

$str = "this is a string that is just some text for you to test with";

print(truncateString($str, 20, false) . "\n");
print(truncateString($str, 22, false) . "\n");
print(truncateString($str, 24, true) . "\n");
print(truncateString($str, 26, true, " :)") . "\n");
print(truncateString($str, 28, true, "--") . "\n");

?>

Output

this is a string tha...
this is a string that ...
this is a string that...
this is a string that is :)
this is a string that is--
9

use explode() .

Example from the docs.

// Example 1
$pizza  = "piece1 piece2 piece3 piece4 piece5 piece6";
$pieces = explode(" ", $pizza);
echo $pieces[0]; // piece1
echo $pieces[1]; // piece2

note that explode has a limit function. So you could do something like

$message = implode(" ", explode(" ", $long_message, 20));
3
  • 2
    Explode's limit function does not act as suggested in this context. See php.net/manual/en/function.explode.php Example #2, positive limit.
    – Aaron
    Commented Jul 6, 2010 at 19:48
  • 3
    @Tegeril is correct. Though this would fix it: $words = implode(" ", array_slice( explode(" ", $t), 0, $count) );
    – Dominik
    Commented Feb 1, 2014 at 0:02
  • 1
    @Dominik, You nailed it. This worked immediately, its simple, very understandable and efficient. Thanks to you and to Tegeril for the first part. Commented Apr 3, 2019 at 19:01
7

Try regex.

You need something that would match 20 words (or 20 word boundaries).

So (my regex is terrible so correct me if this isn't accurate):

/(\w+\b){20}/

And here are some examples of regex in php.

0
7

Simple and fully equiped truncate() method:

function truncate($string, $width, $etc = ' ..')
{
    $wrapped = explode('$trun$', wordwrap($string, $width, '$trun$', false), 2);
    return $wrapped[0] . (isset($wrapped[1]) ? $etc : '');
}
0
5

Its not my own creation, its a modification of previous posts. credits goes to karim79.

function limit_text($text, $limit) {
    $strings = $text;
      if (strlen($text) > $limit) {
          $words = str_word_count($text, 2);
          $pos = array_keys($words);
          if(sizeof($pos) >$limit)
          {
            $text = substr($text, 0, $pos[$limit]) . '...';
          }
          return $text;
      }
      return $text;
    }
5

If you code on Laravel just use Illuminate\Support\Str

here is example

Str::words($category->publication->title, env('WORDS_COUNT_HOME'), '...')

Hope this was helpful.

4

Split the string (into an array) by <space>, and then take the first 20 elements of that array.

9
  • which function would i use to split?
    – sanders
    Commented Jun 8, 2009 at 14:50
  • won't work if there are punctuations but with no space after them, such as "hello,world". Commented Jun 8, 2009 at 14:58
  • 2
    @Jian Lin That's a problem with the user entering poor data, not the script.
    – ceejayoz
    Commented Jun 8, 2009 at 14:59
  • 1
    @Jian just define your delimiter to be all punctuation (,.;) etc
    – z -
    Commented Jun 8, 2009 at 15:01
  • @ceejayoz shouldn't the script handle bad user data too? Commented Jun 8, 2009 at 15:31
4

With triple dots:

function limitWords($text, $limit) {
    $word_arr = explode(" ", $text);

    if (count($word_arr) > $limit) {
        $words = implode(" ", array_slice($word_arr , 0, $limit) ) . ' ...';
        return $words;
    }

    return $text;
}
3

Try below code,

 $text  = implode(' ', array_slice(explode(' ', $text), 0, 32))
 echo $text;
2

Something like this could probably do the trick:

<?php 
$words = implode(' ', array_slice(split($input, ' ', 21), 0, 20));
2

use PHP tokenizer function strtok() in a loop.

$token = strtok($string, " "); // we assume that words are separated by sapce or tab
$i = 0;
$first20Words = '';
while ($token !== false && $i < 20) {
    $first20Words .= $token;
    $token = strtok(" ");
    $i++;
}
echo $first20Words;
2

based on 動靜能量's answer:

function truncate_words($string,$words=20) {
 return preg_replace('/((\w+\W*){'.($words-1).'}(\w+))(.*)/', '${1}', $string);
}

or

function truncate_words_with_ellipsis($string,$words=20,$ellipsis=' ...') {
 $new = preg_replace('/((\w+\W*){'.($words-1).'}(\w+))(.*)/', '${1}', $string);
 if($new != $string){
  return $new.$ellipsis;
 }else{
  return $string;
 }

}
2

This worked me for UNICODE (UTF8) sentences too:

function myUTF8truncate($string, $width){
    if (mb_str_word_count($string) > $width) {
        $string= preg_replace('/((\w+\W*|| [\p{L}]+\W*){'.($width-1).'}(\w+))(.*)/', '${1}', $string);
    }
    return $string;
}
1

Here is what I have implemented.

function summaryMode($text, $limit, $link) {
    if (str_word_count($text, 0) > $limit) {
        $numwords = str_word_count($text, 2);
        $pos = array_keys($numwords);
        $text = substr($text, 0, $pos[$limit]).'... <a href="'.$link.'">Read More</a>';
    }
    return $text;
}

As you can see it is based off karim79's answer, all that needed changing was that the if statement also needed to check against words not characters.

I also added a link to main function for convenience. So far it hsa worked flawlessly. Thanks to the original solution provider.

1

Here's one I use:

    $truncate = function( $str, $length ) {
        if( strlen( $str ) > $length && false !== strpos( $str, ' ' ) ) {
            $str = preg_split( '/ [^ ]*$/', substr( $str, 0, $length ));
            return htmlspecialchars($str[0]) . '&hellip;';
        } else {
            return htmlspecialchars($str);
        }
    };
    return $truncate( $myStr, 50 );
1

Another solution :)

$aContent = explode(' ', $cContent);
$cContent = '';
$nCount = count($aContent);
for($nI = 0; ($nI < 20 && $nI < $nCount); $nI++) {
   $cContent .= $aContent[$nI] . ' ';
}
trim($cContent, ' ');
echo '<p>' . $cContent . '</p>';
1

To limit words, am using the following little code :

    $string = "hello world ! I love chocolate.";
    $explode = array_slice(explode(' ', $string), 0, 4);
    $implode = implode(" ",$explode);   
    echo $implode;

$implot will give : hello world ! I

1
function getShortString($string,$wordCount,$etc = true) 
{
     $expString = explode(' ',$string);
     $wordsInString = count($expString);
     if($wordsInString >= $wordCount )
     {
         $shortText = '';
         for($i=0; $i < $wordCount-1; $i++)
         {
             $shortText .= $expString[$i].' ';
         }
         return  $etc ? $shortText.='...' : $shortText; 
     }
     else return $string;
} 
1

Simpler than all previously posted regex techniques, just match the first n sequences of non-word followed by sequences of word characters. Making the non-word characters optional allows matching of word characters from the start of the string. Greedy word character matching ensures that consecutive word characters are never treated as individual words.

By writing \K in the pattern after matching n substrings, then matching the rest of the string (add the s pattern modifier if you need dots to match newlines), the replacement can be an empty string.

Code: (Demo)

function firstNWords(string $string, int $limit = 3) {
    return preg_replace("/(?:\W*\w+){{$limit}}\K.*/", '', $string);   
}
0

Lets assume we have the string variables $string, $start, and $limit we can borrow 3 or 4 functions from PHP to achieve this. They are:

  • script_tags() PHP function to remove the unnecessary HTML and PHP tags (if there are any). This wont be necessary, if there are no HTML or PHP tags.
  • explode() to split the $string into an array
  • array_splice() to specify the number of words and where it'll start from. It'll be controlled by vallues assigned to our $start and $limit variables.
  • and finally, implode() to join the array elements into your truncated string..

    function truncateString($string, $start, $limit){
        $stripped_string =strip_tags($string); // if there are HTML or PHP tags
        $string_array =explode(' ',$stripped_string);
        $truncated_array = array_splice($string_array,$start,$limit);
        $truncated_string=implode(' ',$truncated_array);
    
        return $truncated_string;
    }
    

It's that simple..

I hope this was helpful.

1
  • What does this add that the literally dozens of answers this question already has doesn't?
    – GordonM
    Commented Jun 20, 2018 at 14:02
0

I made my function:

function summery($text, $limit) {
    $words=preg_split('/\s+/', $text);
     $count=count(preg_split('/\s+/', $text));
      if ($count > $limit) {
          $text=NULL;
          for($i=0;$i<$limit;$i++)
              $text.=$words[$i].' ';
          $text.='...';
      }
      return $text;
    }
0
function limitText($string,$limit){
        if(strlen($string) > $limit){
                $string = substr($string, 0,$limit) . "...";
        }
        return $string;
}

this will return 20 words. I hope it will help

0
0
$text='some text';
$len=strlen($text);
    $limit=500;
// char
    if($len>$limit){
        $text=substr($text,0,$limit);
        $words=explode(" ", $text);
        $wcount=count($words);
        $ll=strlen($words[$wcount]);
        $text=substr($text,0,($limit-$ll+1)).'...';
    }
1
  • Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: stackoverflow.com/help/how-to-answer. Thanks!
    – Matt Ke
    Commented Mar 5, 2019 at 22:21
0
function wordLimit($str, $limit) {
    $arr = explode(' ', $str);
    if(count($arr) <= $limit){
        return $str;   
    }
    $result = '';
    for($i = 0; $i < $limit; $i++){
        $result .= $arr[$i].' ';
    }
    return trim($result);
}
echo wordLimit('Hello Word', 1); // Hello
echo wordLimit('Hello Word', 2); // Hello Word
echo wordLimit('Hello Word', 3); // Hello Word
echo wordLimit('Hello Word', 0); // ''
0

I would go with explode() , array_pop() and implode(), eg.:

$long_message = "I like summer, also I like winter and cats, btw dogs too!";

$trimmed_message = explode(" ", $long_message, 5); // <-- '5' means 4 words to be returned 
array_pop($trimmed_message); //removing last element from exploded array
$trimmed_message = implode(" ", $trimmed_message) . '...';

Result:

I like summer, also...
-1

what about

chunk_split($str,20);

Entry in the PHP Manual

1
  • This is not useful because it doesn't recognize words, just string/character length. Commented Nov 9, 2017 at 22:52
-2
    function limit_word($start,$limit,$text){
            $limit=$limit-1;
            $stripped_string =strip_tags($text);
            $string_array =explode(' ',$stripped_string);
            if(count($string_array)>$limit){
            $truncated_array = array_splice($string_array,$start,$limit);
            $text=implode(' ',$truncated_array).'...';
            return($text);
            }
            else{return($text);}
    }
2
  • 1
    2 answers in two days with only a code sample in a old post. you definitely should read this : stackoverflow.com/help/how-to-answer.
    – Frankich
    Commented Mar 7, 2019 at 14:39
  • Can you explain that further? Why do you need all that code, and what exactly does it do?
    – Nico Haase
    Commented Mar 7, 2019 at 14:50

Not the answer you're looking for? Browse other questions tagged or ask your own question.