Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

substr text without cutting off words

Posted on 2016-09-12
15
Medium Priority
?
70 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
 
LVL 1

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 111

Assisted Solution

by:Ray Paseur
Ray Paseur earned 800 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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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
 
LVL 1

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 59

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
 
LVL 1

Author Comment

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

Accepted Solution

by:
Julian Hansen earned 1200 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
 
LVL 1

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 59

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
 
LVL 1

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 59

Expert Comment

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

You are doing echo twice.
0
 
LVL 1

Author Comment

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

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
 
LVL 1

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

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

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

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…
Introduction This article is intended for those who are new to PHP error handling (https://www.experts-exchange.com/articles/11769/And-by-the-way-I-am-New-to-PHP.html).  It addresses one of the most common problems that plague beginning PHP develop…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

722 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