15

I came up with this function that truncates a given string to either the given number of words or the given number of characters whatever is shorter. Then, after it chops off everything after the number of characters or words limit, it appends a '...' to the string.

How can I remove characters / words from the middle of the string and replace them with '...' instead of replacing characters / words at the end with the '...'?

Here is my code:

function truncate($input, $maxWords, $maxChars){
    $words = preg_split('/\s+/', $input);
    $words = array_slice($words, 0, $maxWords);
    $words = array_reverse($words);

    $chars = 0;
    $truncated = array();

    while(count($words) > 0)
    {
        $fragment = trim(array_pop($words));
        $chars += strlen($fragment);

        if($chars > $maxChars){
            if(!$truncated){
                $truncated[]=substr($fragment, 0, $maxChars - $chars);
            }
            break;
        }

        $truncated[] = $fragment;
    }

    $result = implode($truncated, ' ');

    return $result . ($input == $result ? '' : '...');
}

For example if truncate('the quick brown fox jumps over the lazy dog', 8, 16); is called, 16 characters is shorter so that is the truncation that will happen. So, 'fox jumps over the lazy dog' will be removed and '...' will be appended.

But, instead, how can I have half of the character limit come from the beginning of string and half come from the end of string and what is removed in the middle replaced by '...'? So, the string I'm looking to be return in this, one, case would be: 'the quic...lazy dog'.

irfan mir
  • 373
  • 2
  • 4
  • 10

3 Answers3

36
$text = 'the quick brown fox jumps over the lazy dog';
$textLength = strlen($text);
$maxChars = 16;

$result = substr_replace($text, '...', $maxChars/2, $textLength-$maxChars);

$result is now:

the quic...lazy dog
Ziarno
  • 7,366
  • 5
  • 34
  • 40
7

This won't alter input which is shorter than $maxChars, and takes the length of the replacement ... into account:

function str_truncate_middle($text, $maxChars = 25, $filler = '...')
{
    $length = strlen($text);
    $fillerLength = strlen($filler);

    return ($length > $maxChars)
        ? substr_replace($text, $filler, ($maxChars - $fillerLength) / 2, $length - $maxChars + $fillerLength)
        : $text;
}
crishoj
  • 5,660
  • 4
  • 32
  • 31
3

Here's what I ended up using:

/**
 * Removes characters from the middle of the string to ensure it is no more
 * than $maxLength characters long.
 *
 * Removed characters are replaced with "..."
 *
 * This method will give priority to the right-hand side of the string when
 * data is truncated.
 *
 * @param $string
 * @param $maxLength
 * @return string
 */
function truncateMiddle($string, $maxLength)
{
    // Early exit if no truncation necessary
    if (strlen($string) <= $maxLength) return $string;

    $numRightChars = ceil($maxLength / 2);
    $numLeftChars = floor($maxLength / 2) - 3; // to accommodate the "..."

    return sprintf("%s...%s", substr($string, 0, $numLeftChars), substr($string, 0 - $numRightChars));
}

For my use case the right-hand side of the string contained more useful information so this method is biased towards taking characters out of the left-hand half.

adean
  • 688
  • 5
  • 5