How do I return full words using substr

Hi all

I’ve using a function from a recommendation on php.net and works very well.
My problem is that some words are cut off halfway, example:

The big black dog was eati…
it should read
The big black dog was eating…

Does anybody know how to amend the code below so I will always get full words returned?

function short_name($str, $limit)
  {
    // Make sure a small or negative limit doesn't cause a negative length for substr().
    if ($limit < 3)
    {
      $limit = 3;
    }

    // Now truncate the string if it is over the limit.
    if (strlen($str) > $limit)
    {
      return substr($str, 0, $limit - 3) . '...';
    }
    else
    {
      return $str;
    }
  }

The function in action

$data = l(short_name($node->title, 54),path('node/'.$node->nid));

Thanks, Barry

Hi Barry,

Try this:


function short_name($str, $limit)
{
    if ($limit < 3) $limit = 3;

    if (strlen($str) > $limit) {
    	$str = substr($str, 0, strpos(wordwrap($str, $limit), "\
"));
    }

    return $str;
}

It uses the [fphp]wordwrap[/fphp] function to split the string into lines of a maximum given length, and then returns the first line (based on the solution here).

Works good thanks fretburner :cool:

Just wondering where I can add ‘…’ to the words/titles that exceed the count?

  . '...'

And could you add a couple of comments so I know exactly what’s happening, thanks.

Barry

You can just append them to this line:

$str = substr($str, 0, strpos(wordwrap($str, $limit), "\
")) . '...';

As I said before, the wordwrap function splits a string into lines based on a maximum length argument. If you look at the manual page, you’ll see that by default it won’t split the string mid-word. Once the string is broken into lines, we just use substr to return everything from the beginning of the string up to the first line-break (i.e just the first line) which gives you the result you want.

Good stuff!
Works perfect now fretburner :slight_smile:

Appreciate the detailed information and links thanks.

Barry

Just wondering, not a major issue though some titles look like, example:

someword &…
anotherword -…
anotherword,…

Is there a way to remove certain characters and spaces so everything will always look like:

someword…
anotherword…
anotherword…

Basically if , - & etc. remove them and tighten up to the word.

Cheers, Barry

You can use the [fphp]rtrim[/fphp] function for that… you just need to supply a list of characters that you want removed from the end of the input string.

Impressive.
Just managed to get things to work, very useful fretburner thanks.

If you have a quick look at my updated code below:

if (strlen($str) > $limit) {  
        $str = rtrim(substr($str, 0, strpos(wordwrap($str, $limit), "\
")), ' ,-.&') . '...'; 
    } 

Is this the correct way?
It does works just wondering is this how you would do it?

Thanks, Barry

I’d probably split it into two lines at this point, just to improve readability and avoid the line length getting too long, but it’s a matter of preference rather than a hard and fast rule:

if (strlen($str) > $limit) { 
        $str = substr($str, 0, strpos(wordwrap($str, $limit), "\
"));
        $str = rtrim($str, ' ,-.&') . '...';
}

I’d probably split it into two lines at this point, just to improve readability and avoid the line length getting too long

Absolutely.
I’ve been having this problem with some other code I’ve been working with recently, lines getting to long, hard to read and not sure how to break things up into more digestible snippets. Again, some good information here fretburner still learning PHP thanks.

If you have a minute, what I don’t understand is:

if (strlen($str) > $limit) {  
        $str = substr($str, 0, strpos(wordwrap($str, $limit), "\
")); 
        $str = rtrim($str, ' ,-.&') . '...'; 
}  

We have $str coded twice above and sometimes some code can have the same $variable listed 5 or 6 times.

$str = 0
$str = 1
$str = 2
$str = 3
....

How does this work?
I thought each time the $variable was shown that it would override the $variable before it.

Am I right in saying they append each other, so in theory the above would print 0123.

Barry

That’s right, each time you assign a value to a variable you’re overwriting the previous value.

Looking at the code from your function:

$str = substr($str, 0, strpos(wordwrap($str, $limit), "\
")); 
$str = rtrim($str, ' ,-.&') . '...'; 

We’re passing the original value of $str into a function (or a series of functions) which modify that value. We then reassign this new value back to the original variable.

I’ll have to do a bit of testing and get used to this thanks.

The main reason I ask.
I have the below inside a foreach loop(minimised for viewing) though just realised the .= which is the concatenation assignment string operator, which basically joins together instead of override. Correct?

foreach($nodes as $node) {
    ....
    
    $data = l(short_name($node->title, 54),path('node/'.$node->nid));
    $data .= '<div>';
    $data .= 'some other stuff';
    $data .= '</div>';

    ......
  }

In conclusion then fretburner just so I’ve got this clear, the above would be appended if we use .= and if we use = it would override.

Is this correct?
Do you use .= much yourself.

I’m also using Drupal if that makes any difference.

Thanks, Barry

Yeah, that’s right.

I do sometimes use .= to concatenate strings, although one problem is that it can be hard to spot if you miss out the period, and then your code doesn’t work as you expect.

Cool, and thanks for your time fretburner.

I’m sure this will keep me going for now, until the next problem/thread :cool:

Barry