Solved

substr text without cutting off words

Posted on 2016-09-12
15
55 Views
Last Modified: 2016-09-14
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
Comment
Question by:Black Sulfur
  • 7
  • 4
  • 2
  • +1
15 Comments
 
LVL 31

Expert Comment

by:Marco Gasi
ID: 41794863
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
 

Author Comment

by:Black Sulfur
ID: 41794879
Thanks marco,

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

Warning: strpos(): Offset not contained in string
0
 
LVL 109

Assisted Solution

by:Ray Paseur
Ray Paseur earned 200 total points
ID: 41794885
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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 31

Expert Comment

by:Marco Gasi
ID: 41794899
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
 

Author Comment

by:Black Sulfur
ID: 41794962
Thanks guys, I will try these out and get back to you. Will unfortunately only be tomorrow.
0
 
LVL 55

Expert Comment

by:Julian Hansen
ID: 41794999
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
 

Author Comment

by:Black Sulfur
ID: 41796471
@Julian, your solution doesn't show ... after it truncates the text?
0
 
LVL 55

Accepted Solution

by:
Julian Hansen earned 300 total points
ID: 41796505
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
 

Author Comment

by:Black Sulfur
ID: 41796516
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
 
LVL 55

Expert Comment

by:Julian Hansen
ID: 41796541
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
 

Author Comment

by:Black Sulfur
ID: 41796545
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
 
LVL 55

Expert Comment

by:Julian Hansen
ID: 41796572
Look at Line 13 then look at Line 22

You are doing echo twice.
0
 

Author Comment

by:Black Sulfur
ID: 41796576
Ah. Okay, I fixed that and now it works perfectly :)
0
 
LVL 109

Expert Comment

by:Ray Paseur
ID: 41796832
$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
 

Author Comment

by:Black Sulfur
ID: 41798331
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

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
Build an array called $myWeek which will hold the array elements Today, Yesterday and then builds up the rest of the week by the name of the day going back 1 week.   (CODE) (CODE) Then you just need to pass your date to the function. If i…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to dynamically set the form action using jQuery.

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question