1

I'm trying to build a function to trim a string is it's too long per my specifications.

Here's what I have:

function trim_me($s,$max) 
{
    if (strlen($s) > $max) 
    {
        $s = substr($s, 0, $max - 3) . '...';
    }
    return $s;
}

The above will trim a string if it's longer than the $max and will add a continuation...

I want to expand that function to handle multiple words. Currently it does what it does, but if I have a string say: How are you today? which is 18 characters long. If I run trim_me($s,10) it will show as How are yo..., which is not aesthetically pleasing. How can I make it so it adds a ... after the whole word. Say if I run trim_me($s,10) I want it to display How are you... adding the continuation AFTER the word. Any ideas?

I pretty much don't want to add a continuation in the middle of a word. But if the string has only one word, then the continuation can break the word then only.

user962449
  • 3,743
  • 9
  • 38
  • 53
  • possible duplicate of [How can I truncate a string in PHP?](http://stackoverflow.com/questions/965235/how-can-i-truncate-a-string-in-php) – Stephen Jan 25 '12 at 02:33
  • So `trim_me('a bbbbbbbbbbbbbbbbbbbbbbbb c', 10)` would be `'a bbbbbbbbbbbbbbbbbbbbbbbb...'`? – ruakh Jan 25 '12 at 02:33
  • I get `string(10) "How are..."` for trim_me($s,10) – Aram Kocharyan Jan 25 '12 at 02:34
  • @ruakh no, it's a maximum of 10, so it can be less. It would find the last space and use that I presume? – Aram Kocharyan Jan 25 '12 at 02:36
  • Do you want $max to be the maximum including '...'? That's what your code does, but your examples don't. – Aram Kocharyan Jan 25 '12 at 02:37
  • @AramKocharyan: I don't know how you decided that. The OP gave the example of using `How are you...` instead of `How are yo...` (with the explanation, "adding the continuation AFTER the word"). To me this pretty clearly means that it's a "soft" maximum, and the `...` can be pushed a bit to allow the end of the word. The problem is that, I imagine, there would need to be some upper bound on how far it's O.K. to push it. – ruakh Jan 25 '12 at 02:40
  • @ruakh is correct. It really doesn't matter on the 'upper bound' I can figure that out later I suppose. – user962449 Jan 25 '12 at 02:41
  • @AramKocharyan $max is not included in the string length. – user962449 Jan 25 '12 at 02:43
  • In that case, you could easily specify the maximum length in the caller taking into account the size of the "trunctator" ... – Aram Kocharyan Jan 25 '12 at 03:22

4 Answers4

0
function trim_me($s,$max) {
    if( strlen($s) <= $max) return $s;
    return substr($s,0,strrpos($s," ",$max-3))."...";
}

strrpos is the function that does the magic.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • The function is called `trim_me`, you have an undefined `$c` and I think it's bad practice to have a return at the end of a line following an if without brackets. Generally using an if and else is preferred as it makes your logic explicit and allows extension. – Aram Kocharyan Jan 25 '12 at 02:41
  • Can I blame my keyboard? Or my tiredness? :p – Niet the Dark Absol Jan 25 '12 at 03:18
0

So, here's what you want:

<?php
// Original PHP code by Chirp Internet: www.chirp.com.au 
// Please acknowledge use of this code by including this header.
function myTruncate($string, $limit, $break=".", $pad="...") { 
    // is $break present between $limit and the end of the string? 
    if(false !== ($breakpoint = strpos($string, $break, $limit))) { 
        if($breakpoint < strlen($string) - 1) { 
            $string = substr($string, 0, $breakpoint) . $pad; 
        } 
    } 
    return $string;
}
?>

Also, you can read more at http://www.the-art-of-web.com/php/truncate/

Milos
  • 981
  • 3
  • 16
  • 41
0

I've named the function str_trunc. You can specify strict being TRUE, in which case it will only allow a string of the maximum size and no more, otherwise it will search for the shortest string fitting in the word it was about to finish.

var_dump(str_trunc('How are you today?', 10)); // string(10) "How are..."
var_dump(str_trunc('How are you today? ', 10, FALSE)); // string(14) "How are you..."

// Returns a trunctated version of $str up to $max chars, excluding $trunc.
// $strict = FALSE will allow longer strings to fit the last word.
function str_trunc($str, $max, $strict = TRUE, $trunc = '...') {
    if ( strlen($str) <= $max ) {
        return $str;
    } else {
        if ($strict) {
            return substr( $str, 0, strrposlimit($str, ' ', 0, $max + 1) ) . $trunc;
        } else {
            return substr( $str, 0, strpos($str, ' ', $max) ) . $trunc;
        }
    }
}

// Works like strrpos, but allows a limit
function strrposlimit($haystack, $needle, $offset = 0, $limit = NULL) {
    if ($limit === NULL) {
        return strrpos($haystack, $needle, $offset);
    } else {
        $search = substr($haystack, $offset, $limit);
        return strrpos($search, $needle, 0);
    }
}
hakre
  • 193,403
  • 52
  • 435
  • 836
Aram Kocharyan
  • 20,165
  • 11
  • 81
  • 96
0

It's actually somehow simple and I add this answer because the suggested duplicate does not match your needs (but it does give some pointers).

What you want is to cut a string a maximum length but preserve the last word. So you need to find out the position where to cut the string (and if it's actually necessary to cut it at all).

As getting the length (strlen) and cutting a string (substr) is not your problem (you already make use of it), the problem to solve is how to obtain the position of the last word that is within the limit.

This involves to analyze the string and find out about the offsets of each word. String processing can be done with regular expressions. While writing this, it reminds me on some actually more similar question where this has been already solved:

It does exactly this: Obtaining the "full words" string by using a regular expression. The only difference is, that it removes the last word (instead of extending it). As you want to extend the last word instead, this needs a different regular expression pattern.

In a regular expression \b matches a word-boundary. That is before or after a word. You now want to pick at least $length characters until the next word boundary.

As this could contain spaces before the next word, you might want to trim the result to remove these spaces at the end.

You could extend your function like the following then with the regular expression pattern (preg_replace) and the trim:

/**
 * Cut a string at length while preserving the last word.
 * 
 * @param string $str
 * @param int $length
 * @param string $suffix (optional)
 */
function trim_word($str, $length, $suffix = '...') 
{
    $len = strlen($str);

    if ($len < $length) return $str;

    $pattern = sprintf('/^(.{%d,}?)\b.*$/', $length);
    $str = preg_replace($pattern, '$1', $str);
    $str = trim($str);
    $str .= $suffix;

    return $str;
}

Usage:

$str = 'How are you today?';
echo trim_word($str, 10); # How are you...

You can further on extend this by reducing the minimum length in the pattern by the length of the suffix (as it's somehow suggested in your question, however the results you gave in your question did not match with your code).

I hope this is helpful. Also please use the search function on this site, it's not perfect but many gems are hidden in existing questions for alternative approaches.

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836