72

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

glh
  • 4,900
  • 3
  • 23
  • 40
sanders
  • 10,794
  • 27
  • 85
  • 127
  • 1
    You might find [`s($str)->words(20)`](https://github.com/delight-im/PHP-Str/blob/8fd0c608d5496d43adaa899642c1cce047e076dc/src/Str.php#L363) helpful, as found in [this standalone library](https://github.com/delight-im/PHP-Str). – caw Jul 27 '16 at 00:42

29 Answers29

152
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 ...
Nagy Nick
  • 745
  • 9
  • 19
karim79
  • 339,989
  • 67
  • 413
  • 406
  • 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 Jul 06 '10 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 Jul 06 '10 at 19:42
  • @Tegeril - noted, will delete this post. Thank you. – karim79 Jul 06 '10 at 21:01
  • 2
    `str_word_count` instead of `strlen` should do the trick :) so replace `strlen($text)` with `str_word_count($text,0)` – Val Feb 21 '12 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. – Chris Hanson Sep 23 '13 at 21:19
  • 1
    its working for english, not for Arabic language, i assume not for UTF-8? or am i missing something? – Omar N Shamali Jun 26 '18 at 14:43
  • `[\s]` is more simply written as `\s`. – mickmackusa May 15 '23 at 09:29
34

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(""));  # => ""
Martijn
  • 15,791
  • 4
  • 36
  • 68
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
  • 2
    Amazing this is fastest way so far for word limiting, this performs slighty better than explode, great job, well done. – VeeeneX Jul 01 '15 at 04: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). –  Apr 10 '19 at 00:21
  • To match across lines ```((\w+[\W|\s]*){'.($limit-1).'}\w+|\W|\s)(?:(.*|\s))``` will need trim after for the trailing line breaks – Richard Muvirimi Nov 01 '21 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--
Jacksonkr
  • 31,583
  • 39
  • 180
  • 284
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));
Matthew Vines
  • 27,253
  • 7
  • 76
  • 97
  • 2
    Explode's limit function does not act as suggested in this context. See http://www.php.net/manual/en/function.explode.php Example #2, positive limit. – Aaron Jul 06 '10 at 19:48
  • 3
    @Tegeril is correct. Though this would fix it: `$words = implode(" ", array_slice( explode(" ", $t), 0, $count) );` – Dominik Feb 01 '14 at 00: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. – Samuel Ramzan Apr 03 '19 at 19:01
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 : '');
}
acecream
  • 71
  • 1
  • 2
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.

Assaf Lavie
  • 73,079
  • 34
  • 148
  • 203
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.

Mikayel Margaryan
  • 764
  • 1
  • 7
  • 16
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;
    }
Mixcels
  • 889
  • 1
  • 11
  • 23
rajesh
  • 51
  • 1
  • 1
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;
}
4

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

lance
  • 16,092
  • 19
  • 77
  • 136
3

Try below code,

 $text  = implode(' ', array_slice(explode(' ', $text), 0, 32))
 echo $text;
Jaywant Khedkar
  • 5,941
  • 2
  • 44
  • 55
shunram it
  • 31
  • 3
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;
}
T.Todua
  • 53,146
  • 19
  • 236
  • 237
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;
 }

}
cwd
  • 53,018
  • 53
  • 161
  • 198
2

Something like this could probably do the trick:

<?php 
$words = implode(' ', array_slice(split($input, ' ', 21), 0, 20));
mikl
  • 23,749
  • 20
  • 68
  • 89
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;
farzad
  • 8,775
  • 6
  • 32
  • 41
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>';
thejaeck.net
  • 105
  • 1
  • 4
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

Edouard
  • 21
  • 1
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;
} 
Hamed B
  • 183
  • 1
  • 12
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);   
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
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.

The Thirsty Ape
  • 983
  • 3
  • 16
  • 31
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 );
Johntron
  • 2,443
  • 2
  • 24
  • 26
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.

pamekar
  • 729
  • 7
  • 10
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

Community
  • 1
  • 1
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;
    }
Omar N Shamali
  • 503
  • 5
  • 11
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)).'...';
    }
  • 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](https://stackoverflow.com/help/how-to-answer). Thanks! – Matt Ke Mar 05 '19 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); // ''
An Nguyễn
  • 19
  • 1
  • 4
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...
Sid
  • 4,302
  • 3
  • 26
  • 27
-1

what about

chunk_split($str,20);

Entry in the PHP Manual

fly.floh
  • 420
  • 2
  • 6
-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);}
    }
  • 1
    2 answers in two days with only a code sample in a old post. you definitely should read this : https://stackoverflow.com/help/how-to-answer. – Frankich Mar 07 '19 at 14:39
  • Can you explain that further? Why do you need all that code, and what **exactly** does it do? – Nico Haase Mar 07 '19 at 14:50