72

I have asked a similar question here before, but I need to know if this little tweak is possible. I want to shorten a string to 100 characters and use $small = substr($big, 0, 100); to do so. However, this just takes the first 100 characters and doesn't care whether it breaks up a word or not.

Is there any way to take up to the first 100 characters of a string but make sure you don't break a word?

Example:

$big = "This is a sentence that has more than 100 characters in it, and I want to return a string of only full words that is no more than 100 characters!"

$small = some_function($big);

echo $small;

// OUTPUT: "This is a sentence that has more than 100 characters in it, and I want to return a string of only"

Is there a way to do this using PHP?

Marco Panichi
  • 1,068
  • 1
  • 18
  • 31
JoshFinnie
  • 4,841
  • 7
  • 28
  • 28
  • Try This Link, May help You... http://stackoverflow.com/a/26098951/3944217 – Edwin Thomas Sep 29 '14 at 11:41
  • You might find [`s($str)->truncateSafely(100)`](https://github.com/delight-im/PHP-Str/blob/8fd0c608d5496d43adaa899642c1cce047e076dc/src/Str.php#L246) helpful, as found in [this standalone library](https://github.com/delight-im/PHP-Str). This works for Unicode (is multibyte-safe), by the way. – caw Jul 27 '16 at 00:36

19 Answers19

142

All you need to do is use:

$pos=strpos($content, ' ', 200);
substr($content,0,$pos ); 
Laurel
  • 5,965
  • 14
  • 31
  • 57
amir
  • 1,468
  • 1
  • 10
  • 2
  • 2
    Easy breezy! Eventually put it in a function. Thanks. I will add the rest of the string (for my needs!) $customer_name = substr($customer_name,0,$pos)."
    ".substr($customer_name,$pos,strlen($customer_name));
    – Adrian P. Dec 22 '13 at 20:57
  • 3
    I got `strpos() [function.strpos]: Offset not contained in string` why? – Gediminas Šukys May 22 '14 at 06:32
  • 7
    You're getting that warning because the content is shorter than 200 characters (or whatever limit you decide to set). There's something to be said for not blindly copy pasting code from Stack ;-) – Neil Bryson Jan 16 '15 at 11:15
  • 1
    What if the last word has 20 characters. It will still be taken and will make string bigger than 200 chars – Pratik Joshi Aug 13 '15 at 12:25
  • @Gediminas a wild guess: maybe your string is shorter than 200 chars. – alumi Oct 02 '15 at 03:50
  • 2
    This can make the string longer than the desired limit, as @alumi mentioned. Please see my own answer using strrpos with a negative offset for a better solution. – OMA May 26 '16 at 11:56
  • Would be nice to make this answer more 'safe' since people will tend to copy/paste. For example, what happens if there aren't 200 characters in $content? And, does the answer really "take up to 200 characters"? strpos search starts at character 200 then finds the next space, making the snippet longer than the desired 200 characters (or 100 characters from OP). – ryanm Sep 13 '16 at 11:21
  • Would this not find the position of the first whitespace -after- 200 chars though? What if you want to trim to the last whitespace -before- the limit? – ChristoKiwi Nov 07 '16 at 01:08
  • MADE INTO A FUNCTION: function truncateToWord($content,$length=200){ if(strlen($content)>=$length){ $spaceAtPos = strpos($content, ' ', $length); $content = substr($content,0,$spaceAtPos ); } return $content; } – MaxRocket Mar 24 '17 at 21:26
  • what for remaining words than 200 if i want to catch – Rahul Tathod Oct 05 '18 at 07:04
  • Great, I was just scratching my head for a while because i use mb_substr; I had to change strpos for mb_strpos as well (logic but it escaped me at first) – cdsaenz Oct 07 '20 at 20:31
44

Yes, there is. This is a function I borrowed from a user on a different forums a a few years back, so I can't take credit for it.

//truncate a string only at a whitespace (by nogdog)
function truncate($text, $length) {
   $length = abs((int)$length);
   if(strlen($text) > $length) {
      $text = preg_replace("/^(.{1,$length})(\s.*|$)/s", '\\1...', $text);
   }
   return($text);
}

Note that it automatically adds ellipses, if you don't want that just use '\\1' as the second parameter for the preg_replace call.

TJ L
  • 23,914
  • 7
  • 59
  • 77
  • 4
    that is just a marvelous solution. – Ale Jul 02 '13 at 16:05
  • 1
    This works, except that when the first word is longer than $length, the whole word is returned. So perhaps put `$text = substr($text,0,$length)` first so it gets cut off? – Niclas Feb 10 '14 at 12:54
  • Thanks tj111. This is short and logical and works just sweet. – washere May 03 '17 at 03:25
  • i have tried your function its working fine is there any way to get **last100 characters from string, respecting full words** – ManojKiran A Feb 25 '19 at 10:07
21

If you define words as "sequences of characters delimited by space"... Use strrpos() to find the last space in the string, shorten to that position, trim the result.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
17

This is my approach, based on amir's answer, but it doesn't let any word make the string longer than the limit, by using strrpos() with a negative offset.

Simple but works. I'm using the same syntax as in Laravel's str_limit() helper function, in case you want to use it on a non-Laravel project.

function str_limit($value, $limit = 100, $end = '...')
{
    $limit = $limit - mb_strlen($end); // Take into account $end string into the limit
    $valuelen = mb_strlen($value);
    return $limit < $valuelen ? mb_substr($value, 0, mb_strrpos($value, ' ', $limit - $valuelen)) . $end : $value;
}
OMA
  • 3,442
  • 2
  • 32
  • 39
  • 4
    Yes I agree this is better than Amir's answer because it respects the exact limit. But to further improve the answer you may consider using Multibyte character functions "mb_" to support Multibyte characters like Arabic language characters. As your function will fail if you used a multibyte characters in the test string. Use "mb_strlen(), mb_substr(), mb_strpos" instead of "strlen(), substr(), strrpos()"/. – Yacoub Oweis Jun 01 '16 at 12:57
13

Sure. The easiest is probably to write a wrapper around preg_match:

function limitString($string, $limit = 100) {
    // Return early if the string is already shorter than the limit
    if(strlen($string) < $limit) {return $string;}

    $regex = "/(.{1,$limit})\b/";
    preg_match($regex, $string, $matches);
    return $matches[1];
}

EDIT : Updated to not ALWAYS include a space as the last character in the string

PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94
11

This function shortens a string by adding "..." at a word boundary whenever possible. The returned string will have a maximum length of $len including "...".

function truncate($str, $len) {
  $tail = max(0, $len-10);
  $trunk = substr($str, 0, $tail);
  $trunk .= strrev(preg_replace('~^..+?[\s,:]\b|^...~', '...', strrev(substr($str, $tail, $len-$tail))));
  return $trunk;
}

Examples outputs:

  • truncate("Thanks for contributing an answer to Stack Overflow!", 15)
    returns "Thanks for..."
  • truncate("To learn more, see our tips on writing great answers.", 15)
    returns "To learn more..." (comma also truncated)
  • truncate("Pseudopseudohypoparathyroidism", 15)
    returns "Pseudopseudo..."
filip
  • 3,542
  • 1
  • 26
  • 23
4

Here is great solution with dotts at the end with full words

function text_cut($text, $length = 200, $dots = true) {
    $text = trim(preg_replace('#[\s\n\r\t]{2,}#', ' ', $text));
    $text_temp = $text;
    while (substr($text, $length, 1) != " ") { $length++; if ($length > strlen($text)) { break; } }
    $text = substr($text, 0, $length);
    return $text . ( ( $dots == true && $text != '' && strlen($text_temp) > $length ) ? '...' : ''); 
}

Input: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Output: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip...

4

This works fine for me, I use it in my script

<?PHP
$big = "This is a sentence that has more than 100 characters in it, and I want to return a string of only full words that is no more than 100 characters!";
$small = some_function($big);
echo $small;

function some_function($string){
     $string = substr($string,0,100);
     $string = substr($string,0,strrpos($string," "));
     return $string;
}
?>

good luck

ahmed
  • 14,316
  • 30
  • 94
  • 127
3
function truncate ($str, $length) {
    if (strlen($str) > $length) {
        $str = substr($str, 0, $length+1);
        $pos = strrpos($str, ' ');
        $str = substr($str, 0, ($pos > 0)? $pos : $length);
    }
    return $str;
}

Example:

print truncate('The first step to eternal life is you have to die.', 25);

string(25) "The first step to eternal"

print truncate('The first step to eternal life is you have to die.', 12);

string(9) "The first"

print truncate('FirstStepToEternalLife', 5);

string(5) "First"

Aigars Matulis
  • 1,469
  • 17
  • 22
3

The problem with accepted answer is that result string goes over the the limit, i.e. it can exceed 100 chars since strpos will look after the offset and so your length will always be a over your limit. If the last word is long, like squirreled then the length of your result will be 111 (to give you an idea).

A better solution is to use wordwrap function:

function truncate($str, $length = 125, $append = '...') {
    if (strlen($str) > $length) {
        $delim = "~\n~";
        $str = substr($str, 0, strpos(wordwrap($str, $length, $delim), $delim)) . $append;
    } 

    return $str;
}


echo truncate("The quick brown fox jumped over the lazy dog.", 5);

This way you can be sure the string is truncated under your limit (and never goes over)

P.S. This is particularly useful if you plan to store the truncated string in your database with a fixed-with column like VARCHAR(50), etc.

P.P.S. Note the special delimiter in wordwrap. This is to make sure that your string is truncated correctly even when it contains newlines (otherwise it will truncate at first newline which you don't want).

supersan
  • 5,671
  • 3
  • 45
  • 64
2

This did it for me...

//trim message to 100 characters, regardless of where it cuts off
$msgTrimmed = mb_substr($var,0,100);

//find the index of the last space in the trimmed message
$lastSpace = strrpos($msgTrimmed, ' ', 0);

//now trim the message at the last space so we don't cut it off in the middle of a word
echo mb_substr($msgTrimmed,0,$lastSpace)
katfish
  • 21
  • 1
2

Here's my solution:

/**
 * get_words_until() Returns a string of delimited text parts up to a certain length
 * If the "words" are too long to limit, it just slices em up to the limit with an ellipsis "..."
 *
 * @param $paragraph - The text you want to Parse
 * @param $limit - The maximum character length, e.g. 160 chars for SMS
 * @param string $delimiter - Use ' ' for words and '. ' for sentences (abbreviation bug) :)
 * @param null $ellipsis - Use '...' or ' (more)' - Still respects character limit
 *
 * @return string
 */
function get_words_until($paragraph, $limit, $delimiter = ' ', $ellipsis = null)
{
    $parts = explode($delimiter, $paragraph);

    $preview = "";

    if ($ellipsis) {
        $limit = $limit - strlen($ellipsis);
    }

    foreach ($parts as $part) {
        $to_add = $part . $delimiter;
        if (strlen($preview . trim($to_add)) <= $limit) { // Can the part fit?
            $preview .= $to_add;
            continue;
        }
        if (!strlen($preview)) { // Is preview blank?
            $preview = substr($part, 0, $limit - 3) . '...'; // Forced ellipsis
            break;
        }
    }

    return trim($preview) . $ellipsis;
}

In your case it would be (example):

$big = "This is a sentence that has more than 100 characters in it, and I want to return a string of only full words that is no more than 100 characters!"

$small = get_words_until($big, 100);
Kevin K
  • 59
  • 1
2

Here is another way you can do that.

$big = "This is a sentence that has more than 100 characters in it, and I want to return a string of only full words that is no more than 100 characters!"
$big = trim( $big );
$small = $big;
                if( strlen( $big ) > 100 ){
                $small = mb_substr( $small, 0, 100 );
                $last_position = mb_strripos( $small, ' ' );
                    if( $last_position > 0 ){
                    $small = mb_substr( $small, 0, $last_position );
                    }
                }

            echo $small; 

OR

 echo ( strlen( $small ) <  strlen( $big ) ? $small.'...' : $small );

This is also multibyte safe and also works even if there are not spaces, in which case it will just simply return first 100 characters. It takes the first 100 characters and then searches from the end till the nearest word delimiter.

Alex
  • 21
  • 1
1

I apologize for resurrecting this question but I stumbled upon this thread and found a small issue. For anyone wanting a character limit that will remove words that would go above your given limit, the above answers work great. In my specific case, I like to display a word if the limit falls in the middle of said word. I decided to share my solution in case anyone else is looking for this functionality and needs to include words instead of trimming them out.

function str_limit($str, $len = 100, $end = '...')
{
    if(strlen($str) < $len)
    {
        return $str;
    }

    $str = preg_replace("/\s+/", ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));

    if(strlen($str) <= $len)
    {
        return $str;
    }

    $out = '';
    foreach(explode(' ', trim($str)) as $val)
    {
        $out .= $val . ' ';

        if(strlen($out) >= $len)
        {
            $out = trim($out);
            return (strlen($out) == strlen($str)) ? $out : $out . $end;
        }
    }
}

Examples:

  • Input: echo str_limit('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 100, '...');
  • Output: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore...
  • Input: echo str_limit('Lorem ipsum', 100, '...');
  • Output: Lorem ipsum
  • Input: echo str_limit('Lorem ipsum', 1, '...');
  • Output: Lorem...
beaudierman
  • 138
  • 1
  • 9
1

Yet another answer! I wasn't completely satisfied with other answers, and wanted a 'hard cutoff' (guaranteed word break before $max_characters, if possible), so here's my function to contribute!

/**
 * Shortens a string (if necessary), trying for a non-word character before character limit, adds an ellipsis and
 * returns. Falls back to a forced cut if no non-word characters exist before.
 *
 * @param string $content
 * @param int    $max_characters - number of characters to start looking for a space / break.
 * @param bool   $add_ellipsis   - add ellipsis if content is shortened
 *
 * @return string
 */
public static function shorten( $content, $max_characters = 100, $add_ellipsis = TRUE ) {
    if ( strlen( $content ) <= $max_characters ) {
        return $content;
    }

    // search for non-word characters
    $match_count = preg_match_all( '/\W/', $content, $matches, PREG_OFFSET_CAPTURE );

    // force a hard break if can't find another good solution
    $pos = $max_characters;

    if ( $match_count > 0 ) {
        foreach ( $matches[0] as $match ) {
            // check if new position fits within
            if ( $match[1] <= $max_characters ) {
                $pos = $match[1];
            } else {
                break;
            }
        }
    }

    $suffix = ( $add_ellipsis ) ? '&hellip;' : '';

    return substr( $content, 0, $pos ) . $suffix;
}
ryanm
  • 2,239
  • 21
  • 31
1

## Get first limited character from a string ##

<?php 
  $content= $row->title;
  $result = substr($content, 0, 70);
  echo $result; 
  ?>
1

Another a simpler way I do.

function limit_words($string, $word_limit = 10)
{
    $words = explode(" ", $string);
    if (count($words) > $word_limit) {
        return implode(" ", array_splice($words, 0, $word_limit)) . ' ...';
    }
    return implode(" ", array_splice($words, 0, $word_limit));
}
zarpio
  • 10,380
  • 8
  • 58
  • 71
0

wordwrap formats string according to limit, seprates them with \n so we have lines smaller than 50, ords are not seprated explodes seprates string according to \n so we have array corresponding to lines list gathers first element.

list($short) = explode("\n",wordwrap($ali ,50));

please rep Evert, since I cant comment or rep.

here is sample run

php >  $ali = "ali veli krbin yz doksan esikesiksld sjkas laksjald lksjd asldkjadlkajsdlakjlksjdlkaj aslkdj alkdjs akdljsalkdj ";
php > list($short) = explode("\n",wordwrap($ali ,50));
php > var_dump($short);
string(42) "ali veli krbin yz doksan esikesiksld sjkas"
php > $ali ='';
php > list($short) = explode("\n",wordwrap($ali ,50));
php > var_dump($short);
string(0) ""
Community
  • 1
  • 1
nerkn
  • 1,867
  • 1
  • 20
  • 36
0
$st = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy";
$charNo =100;
echo myFun($st,$charNo);

function myFun($st,$charNo){
   $di ='';
   if (strlen($st)>$charNo) {
     $di ='...';
  }
  $line = substr($st, 0, $charNo).$di;
  return $line;
}

OUTPUT => Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the ...