• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 99
  • Last Modified:

substr text without cutting off words

I am creating a blog and on the page that lists a bunch of articles there is a bit of the article followed by.... and a "read more" button.

My problem is that what I have done cuts words off. Is is possible to get it to show a complete word and then... as opposed to for example a bit of a word e.g.:   the big, grey eleph......

$post_content = substr($post_content_safe,0,100);

Open in new window

0
Black Sulfur
Asked:
Black Sulfur
  • 7
  • 4
  • 2
  • +1
2 Solutions
 
Marco GasiFreelancerCommented:
This could be a possible solution:
$pos=strpos($content, ' ', 100);
substr($content,0,$pos ); 

Open in new window

WIth the first line you get the index of the first occurrence of a blank space in the given string starting the search  from the character 100. The second line get the text starting from 0 to the value of the blank space found with the first line. This will likely give you a string longer than 100 so you could use a lower value, maybe 90?

Here you find a function written using this tecnique: http://www.ebrueggeman.com/blog/abbreviate-text-without-cutting-words-in-half
0
 
Black SulfurAuthor Commented:
Thanks marco,

I tried your code before the one on the link and get error:

Warning: strpos(): Offset not contained in string
0
 
Ray PaseurCommented:
Check this function.  What you're asking for is called a "teaser fragment" in the publishing industry.  Here's how it's done.
https://iconoun.com/demo/teaser_fragment.php
<?php // demo/teaser_fragment.php
/**
 * Create a teaser fragment headline.
 * Return first few whole words followed by ellipses,
 * with a link to the full article.
 * "$length" is minimum truncation character count
 */
error_reporting(E_ALL);


function teaser_fragment($text, $length=32, $url='#', $delim='|||')
{
    // IF TRUNCATION IS NEEDED
    if (strlen($text) > $length)
    {
        // IF TRUNCATION IS NEEDED, BREAK STRING APART
        $t = wordwrap($text, $length, $delim);
        $a = explode($delim, $t);
        $z = '...';
    }
    // IF TRUNCATION IS NOT NEEDED
    else
    {
        $a[0] = $text;
        $z = NULL;
    }

    // CONSTRUCT THE FRAGMENT WITH THE LINK AND ADD ELLIPSIS (LINK) TO THE END
    $teaser
    = '<a target="_blank" href="'
    . $url
    . '">'
    . $a[0]
    . $z
    . '</a>'
    ;
    return $teaser;
}


// USE CASES
$headline = 'Now is the time for all good men to come to the aid of their party';
echo "<pre>";
echo PHP_EOL;
echo "1...5...10...15...20...25...30...35...40...45..." . PHP_EOL;
echo teaser_fragment($headline);

echo PHP_EOL;
echo teaser_fragment($headline, 300);

echo PHP_EOL;
echo teaser_fragment($headline, 15, 'http://en.wikipedia.org/wiki/Filler_text');

Open in new window

0
Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

 
Marco GasiFreelancerCommented:
The do a check before (like in a function I linked above)
if(strlen($post_content_safe) >= 100 ){
    $pos=strpos($content, ' ', 100);
    $post_content = substr($post_content_safe,0,$pos ); 
}else{
   $post_content = $post_content_safe;
}

Open in new window

0
 
Black SulfurAuthor Commented:
Thanks guys, I will try these out and get back to you. Will unfortunately only be tomorrow.
0
 
Julian HansenCommented:
Another option is this (for interest)
$str = "The quick brown fox jumps over the lazy dog and the whale with the tail jumped into the pail";
$teaser = cutoff($str, 40);
function cutoff($s, $len)
{
   if (strlen($s) <= $len) return $s;
   for($i = $len; $i > 0 && $s[$i] != ' '; $i--);

   return substr($s, 0, $i);
}

Open in new window

About 33% more efficient.
0
 
Black SulfurAuthor Commented:
@Julian, your solution doesn't show ... after it truncates the text?
0
 
Julian HansenCommented:
Then just add an echo statement to see what is in the string.
$str = "The quick brown fox jumps over the lazy dog and the whale with the tail jumped into the pail";
$teaser = cutoff($str, 40);
echo $teaser;
function cutoff($s, $len)
{
   if (strlen($s) <= $len) return $s;
   for($i = $len; $i > 0 && $s[$i] != ' '; $i--);

   return substr($s, 0, $i);
}

Open in new window

0
 
Black SulfurAuthor Commented:
I just added ... after echoing $teaser. Am I meant to echo $teaser?

echo $teaser."...";

Open in new window


It works but just want to double check that $teaser is what I should be echoing.
0
 
Julian HansenCommented:
The function cutoff() does the work and returns the trimmed text - so you call that function with the original string and the max length you want it to be and it returns the truncated string.

[Aside: cutoff is a bit of a lame name - brain was on strike - truncate might be better]

So long story short $teaser is what you should be echo ing out.
0
 
Black SulfurAuthor Commented:
Okay, here is where I am at. I could not get Marco's solution to work (I didn't try out that external link of his). I got Ray's example to work using my database. And I got Julian's example to work from the database except that for some reason it repeats content i.e.

But I must explain to you how all thisBut I must explain to you how all this...

Julian Code:

$sql = "SELECT * FROM `posts`";
$result = $link->query($sql);
if($result->num_rows > 0){
	while($row = $result->fetch_assoc()){
		
		$post_content = htmlentities($row['post_content']);
	}
}


$str = $post_content;
$teaser = cutoff($str, 40);
echo $teaser;
function cutoff($s, $len)
{
   if (strlen($s) <= $len) return $s;
   for($i = $len; $i > 0 && $s[$i] != ' '; $i--);

   return substr($s, 0, $i);
}

echo $teaser."...";

Open in new window


Ray's code:

$sql = "SELECT * FROM `posts`";
$result = $link->query($sql);
if($result->num_rows > 0){
	while($row = $result->fetch_assoc()){
		
		$post_content = htmlentities($row['post_content']);
	}
}

function teaser_fragment($text, $length=32, $url='#', $delim='|||')
{
    // IF TRUNCATION IS NEEDED
    if (strlen($text) > $length)
    {
        // IF TRUNCATION IS NEEDED, BREAK STRING APART
        $t = wordwrap($text, $length, $delim);
        $a = explode($delim, $t);
        $z = '...';
    }
    // IF TRUNCATION IS NOT NEEDED
    else
    {
        $a[0] = $text;
        $z = NULL;
    }

    // CONSTRUCT THE FRAGMENT WITH THE LINK AND ADD ELLIPSIS (LINK) TO THE END
    $teaser
    = '<a target="_blank" href="'
    . $url
    . '">'
    . $a[0]
    . $z
    . '</a>'
    ;
    return $teaser;
}


// USE CASES
$headline = $post_content;
echo "<pre>";
echo PHP_EOL;
echo "1...5...10...15...20...25...30...35...40...45..." . PHP_EOL;
echo teaser_fragment($headline);

echo PHP_EOL;
echo teaser_fragment($headline, 300);

echo PHP_EOL;
echo teaser_fragment($headline, 25, 'http://en.wikipedia.org/wiki/Filler_text');

Open in new window

0
 
Julian HansenCommented:
Look at Line 13 then look at Line 22

You are doing echo twice.
0
 
Black SulfurAuthor Commented:
Ah. Okay, I fixed that and now it works perfectly :)
0
 
Ray PaseurCommented:
$sql = "SELECT * FROM `posts`";
If you have something like SELECT * in your code, you need to start understanding why we avoid antipatterns!
https://www.experts-exchange.com/articles/12293/AntiPHPatterns-and-AntiPHPractices.html
0
 
Black SulfurAuthor Commented:
Oh yes, sorry. I was doing a tutorial that had * in it for simplicity's sake. In real world applications I certainly won't use * but thanks for the link!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 7
  • 4
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now