How to trim words by character limit

We recently encountered a scenario where the client wanted to trim the news items titles to a maximum number of characters, whilst respecting words.

Our research revealed that this seemingly obvious requirement wasn’t elegantly solved. As most of you will know, there are solutions for trimming by characters or trimming by words, but neither of these fulfilled our requirements of trimming by characters, but keeping output to full words.

Introducing trim_respect_words

function trim_respect_words(string $string, int $char_length = 50) :string {
    // trim edges
    $string = trim($string);

    // store string length
    $str_len = strlen($string);

    // leave if the string is within the limit
    if ($char_length >= $str_len) return $string;

    // split the words into an array
    $words = explode(' ', $string);

    // record the current position in the words array
    $word_count = 0;

    // prepare the string
    $string = '';

    // build the string back up, until the character limit is reached
    while ($char_length > $str_len) {
        $string .= "{$words[$word_count]} ";
        $word_count++;
    }

    // remove the last character (space)
    $string = substr($string, 0, -1);

    // if the string now exceeds limit, remove the last word
    if ($char_length <= $str_len) {

        // position (from right) of the first space
        $last_word = strrpos($string, " ");

        // remove last word
        $string = substr($string, 0, $last_word);
    }

    // return trimmed string with any special characters removed from the end and replaced with ellipsis
    return preg_replace('/[^a-z0-9]+\Z/i', '', $string). '…';
}

Notes about this code

  • I’ve deliberately avoided using substr to get the sub string of the original string, as using elements of an array is more robust.
  • The last space added in the while loop needs to be remove before checking if the last word added has pushed the string over the limit
  • The last word added will almost definitely push the string over the character limit, but just removing it is more efficient than adding complexity to the while loop’s body – the overheads would include an if statement, a string length calculation on the current word and a comparison of the word’s impact on the string’s length – all for each iteration

Uses for trim_respect_words

This code could be used as a simple function, or as part of a class, or, if you’re using WordPress, a hook that conditionally hangs itself off the get_title() function’s filter. Ping us a line if you’d like to know how to do this as, amongst other talents, we’re seasoned WordPress developers.