68

I know how to use the substr function but this will happy end a string halfway through a word. I want the string to end at the end of a word how would I go about doing this? Would it involve regular expression? Any help very much appreciated.

This is what I have so far. Just the SubStr...

echo substr("$body",0,260);

Cheers

Cool Hand Luke
  • 2,120
  • 9
  • 32
  • 51

11 Answers11

144
substr($body, 0, strpos($body, ' ', 260))
j0k
  • 22,600
  • 28
  • 79
  • 90
Achshar
  • 5,153
  • 8
  • 40
  • 70
  • 1
    Stylish solution, but what about UTF-8? – Tony Bogdanov Nov 23 '12 at 12:13
  • Yes but wouldn't strpos get confused since now 260 is actually 130 characters? – Tony Bogdanov Dec 15 '12 at 15:00
  • 16
    Using this can generate a strpos warning if the text is shorter than 260 chars. – emrahgunduz Jun 07 '13 at 08:44
  • 4
    There are many issues with this. As mentioned, it fails if the string is less than the 260 character length, or if it doesn't contain any spaces. It also doesn't limit the string to 260 characters, instead it breaks the string at the space *after* 260 characters, which is usually not what you want. It also doesn't work if the word break is a different type of whitespace such as a tab or newline. It also isn't multibyte compatible. Paul Dixon's preg_match() solution was a better solution. – orrd Sep 01 '15 at 20:31
  • The answer of @zed corrects the issue that this solution has about exceeding the character limit. – RayOnAir Jul 02 '16 at 21:53
  • What about languages that don't use a space to separate words? – Timo Huovinen Oct 20 '20 at 14:43
  • on php8, if the string is less than 260 it's not generating a warning - it generates fatal error and crash – sd1sd1 Sep 11 '21 at 15:09
114

It could be done with a regex, something like this will get up to 260 characters from the start of string up to a word boundary:

$line=$body;
if (preg_match('/^.{1,260}\b/s', $body, $match))
{
    $line=$match[0];
}

Alternatively, you could maybe use the wordwrap function to break your $body into lines, then just extract the first line.

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • I think they may have down voted because its not using PHP who knows. Works so thanks. – Cool Hand Luke Aug 06 '09 at 18:52
  • 2
    What about UTF8? I'm so bad with Regex. – Sobiaholic Jul 29 '13 at 23:17
  • 9
    Try using the /u modifier for matching UTF-8, e.g. `/^.{1,260}\b/su` – Paul Dixon Jul 30 '13 at 08:59
  • In my case, this didn't work 100%. It never fails the if statement. So if I have a string that's less than 260 characters, it still passes. any suggestions? – Florin Vistig Jul 30 '13 at 09:15
  • 1
    well, even if it's less than 260 chars, it still breaks on a word boundary, so produces a valid result. But you could just check the string length before you try the regex. – Paul Dixon Jul 30 '13 at 09:40
  • 1
    This seems to work well. One edge case to be aware of, if there is no whitespace character at all in the first 260 characters, it just returns the whole string. If that's an issue, you can add something like `$line = mb_substr($line, 0, 260);` to force a break at that length. – orrd Sep 01 '15 at 20:25
  • if we give summary of article in this way, dots `...` should be added, but these dots sometimes is after whitespace, like:`last word ...` if we just add the dots in this way `$match[0].'...';` – Gediminas Šukys Jun 13 '17 at 05:59
  • Add ` && strlen($body) >= 260` to the `if`. Then you can change the rule to `$line=$match[0].' …';` and dots are added only to shortened strings. – Fanky Sep 11 '19 at 10:16
  • Does this work with other languages? For example Russian? – Timo Huovinen Oct 20 '20 at 15:12
43

You can try this:

   $s = substr($string, 0, 261);
   $result = substr($s, 0, strrpos($s, ' '));
Michiel
  • 7,855
  • 16
  • 61
  • 113
Zed
  • 57,028
  • 9
  • 76
  • 100
  • 6
    This is the best answer! Contrary to @achshar solution, this solution allows preserving whole words while not exceeding the word limit. The key is to use the `strrpos` function to look for the last white space in the first 261 chars, return that position, and then slice the string at that position with `substr`. Remember to include all that in an `if` statement to apply the functions only if the text is greater than 260 chars. – RayOnAir Jul 02 '16 at 17:37
  • This solution can be more perfect (I guess) by not +1 to the `substr()`, but to check if the last char is a space or not. So here is my suggestion to the 2nd line: `$result = substr($s, -1) === " " ? trim($s) : substr($s, 0, strrpos($s, ' '));` – Ellery Leung Jun 15 '21 at 02:59
13

You could do this: Find the first space from the 260th character on and use that as the crop mark:

$pos = strpos($body, ' ', 260);
if ($pos !== false) {
    echo substr($body, 0, $pos);
}
Gumbo
  • 643,351
  • 109
  • 780
  • 844
5

wordwrap and explode then first array element is you want $wr=wordwrap($text,20,':'); $strs=explode(":",$wr); $strs[0]

  • 3
    I think this is the cleanest solution, even a one liner - `echo explode('||',wordwrap($text,20,'||'))[0]` – cornernote Sep 08 '20 at 02:53
1

I use this solution:

$maxlength = 50;
substr($name, 0, ($spos = strpos($name, ' ', $lcount = count($name) > $maxlength ? $lcount : $maxlength)) ? $spos : $lcount );

Or inline:

substr($name, 0, ($spos = strpos($name, ' ', $lcount = count($name) > 50 ? $lcount : 50)) ? $spos : $lcount );
Oleksandr Knyga
  • 625
  • 9
  • 9
1
function substr_word($body,$maxlength){
    if (strlen($body)<$maxlength) return $body;
    $body = substr($body, 0, $maxlength);
    $rpos = strrpos($body,' ');
    if ($rpos>0) $body = substr($body, 0, $rpos);
    return $body;
}
Sanne
  • 1,116
  • 11
  • 17
1

What about this?

/**
 * @param string $text
 * @param int $limit
 * @return string
 */
public function extractUncutPhrase($text, $limit)
{
    $delimiters = [',',' '];
    $marks = ['!','?','.'];

    $phrase = substr($text, 0, $limit);
    $nextSymbol = substr($text, $limit, 1);


    // Equal to original
    if ($phrase == $text) {
        return $phrase;
    }
    // If ends with delimiter
    if (in_array($nextSymbol, $delimiters)) {
        return $phrase;
    }
    // If ends with mark
    if (in_array($nextSymbol, $marks)) {
        return $phrase.$nextSymbol;
    }

    $parts = explode(' ', $phrase);
    array_pop($parts);

    return implode(' ', $parts); // Additioanally you may add ' ...' here.
}

Tests:

public function testExtractUncutPhrase()
{
    $stringUtils = new StringUtils();

    $text = 'infant ton-gue could make of both names nothing';
    $phrase = 'infant';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 11));
    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 12));

    $text = 'infant tongue5';
    $phrase = 'infant';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 13));
    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 11));
    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 7));
}

public function testExtractUncutPhraseEndsWithDelimiter()
{
    $stringUtils = new StringUtils();

    $text = 'infant tongue ';
    $phrase = 'infant tongue';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 13));

    $text = 'infant tongue,';
    $phrase = 'infant tongue';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 13));
}

public function testExtractUncutPhraseIsSentence()
{
    $stringUtils = new StringUtils();

    $text = 'infant tongue!';
    $phrase = 'infant tongue!';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 14));
    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 100));

    $text = 'infant tongue!';
    $phrase = 'infant tongue!';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 13));

    $text = 'infant tongue.';
    $phrase = 'infant tongue.';

    $this->assertEquals($phrase, $stringUtils->extractUncutPhrase($text, 13));
}
Ivan Proskuryakov
  • 1,625
  • 2
  • 23
  • 32
0
$pos = strpos($body, $wordfind);
echo substr($body,0, (($pos)?$pos:260));
andres descalzo
  • 14,887
  • 13
  • 64
  • 115
-1
public function Strip_text($data, $size, $lastString = ""){
    $data = strip_tags($data);          
    if(mb_strlen($data, 'utf-8') > $size){
        $result = mb_substr($data,0,mb_strpos($data,' ',$size,'utf-8'),'utf-8');
            if(mb_strlen($result, 'utf-8') <= 0){
            $result = mb_substr($data,0,$size,'utf-8');
            $result = mb_substr($result, 0, mb_strrpos($result, ' ','utf-8'),'utf-8');;         
        }
        if(strlen($lastString) > 0) {
            $result .= $lastString;
        }
    }else{
    $result = $data;
    }
    return $result; 
}

Pass the string into funtion Strip_text("Long text with html tag or without html tag", 15) Then this function will return the first 15 character from the html string without html tags. When string less than 15 character then return the full string other wise it will return the 15 character with $lastString parameter string.

Example:

Strip_text("<p>vijayDhanasekaran</p>", 5)

Result: vijay

Strip_text("<h1>vijayDhanasekaran<h1>",5,"***....")

Result: vijay***....

vijay
  • 329
  • 2
  • 8
-2

Try This Function..

<?php
/**
 * trims text to a space then adds ellipses if desired
 * @param string $input text to trim
 * @param int $length in characters to trim to
 * @param bool $ellipses if ellipses (...) are to be added
 * @param bool $strip_html if html tags are to be stripped
 * @param bool $strip_style if css style are to be stripped
 * @return string
 */
function trim_text($input, $length, $ellipses = true, $strip_tag = true,$strip_style = true) {
    //strip tags, if desired
    if ($strip_tag) {
        $input = strip_tags($input);
    }

    //strip tags, if desired
    if ($strip_style) {
        $input = preg_replace('/(<[^>]+) style=".*?"/i', '$1',$input);
    }

    if($length=='full')
    {

        $trimmed_text=$input;

    }
    else
    {
        //no need to trim, already shorter than trim length
        if (strlen($input) <= $length) {
        return $input;
        }

        //find last space within length
        $last_space = strrpos(substr($input, 0, $length), ' ');
        $trimmed_text = substr($input, 0, $last_space);

        //add ellipses (...)
        if ($ellipses) {
        $trimmed_text .= '...';
        }       
    }

    return $trimmed_text;
}
?>
Edwin Thomas
  • 1,186
  • 2
  • 18
  • 31