Truncate long lines, no word break with dot interpolation

I'm trying to truncate a long string to a certain number of characters, and interpolate another user-defined string in the middle (more or less) to represent that the string has been truncated. And at the same time, I try to make the words not break in half. For example:

The quick brown fox jumped over the lazy dog

If defined (as a function parameter) to truncate this string to 20 characters, the resulting string should look something like this:

The fast brown ... lazy dog

The closest implementation I came to was as follows:

function truncate( $string, $length, $append = NULL ) {

    if( strlen( $string ) <= $length ) return $string;

    $append = ( strlen( $append ) ? sprintf( ' %s ', $append ) : ' ... ' );

    $start = round( $length / 2 );
    $start = strlen( substr( $string, 0, ( strpos( substr( $string, $start ), ' ' ) + $start ) ) );

    $end = ( $start - strlen( $append ) );
    $end = strlen( substr( $string, 0, strrpos( substr( $string, $start + strlen( $append ) - 1 ), ' ' ) ) );

    return substr( $string, 0, $start ) . $append . substr( $string, ( strlen( $string ) - $end ) );
}

      

Not only does this not work smoothly with strings of different lengths, it also does not truncate the size as defined.

For some strings, I get duplicate blanks (due to incorrect math about spaces used by sprintf () over $ append ), sometimes one letter is removed from the word closest to the interpolated string, and sometimes the word is split in half when it shouldn't.

The above line, for example, if used like:

truncate( $str, 20 );

      

Results in:

Fast brown ... singing over a lazy dog

+3


source to share


1 answer


To avoid truncating the middle word, I look first wordwrap()

as it already has this ability by default.

Thus, the approach I would use instead is to use wordwrap()

to split the string into segments around half of your entire desired length, minus the length of the delimiter string.

Then concatenate the first line from wordwrap()

, delimiter and last line. (Use explode()

to split the output wordwrap()

into lines).

// 3 params: input $string, $total_length desired, $separator to use
function truncate($string, $total_length, $separator) {
  // The wordwrap length is half the total minus the separator length
  // trim() is used to prevent surrounding space on $separator affecting the length
  $len = ($total_length - strlen(trim($separator))) / 2;

  // Separate the output from wordwrap() into an array of lines
  $segments = explode("\n", wordwrap($string, $len));

  // Return the first, separator, last
  return reset($segments) . $separator . end($segments);
}

      

Try it: http://codepad.viper-7.com/ai6mAK

$s1 = "The quick brown fox jumped over the lazy dog";
$s2 = "Lorem ipsum dolor sit amet, nam id laudem aliquid. Option utroque interpretaris eu sea, pro ea illud alterum, sed consulatu conclusionemque ei. In alii diceret est. Alia oratio ei duo.";
$s3 = "This is some other long string that ought to get truncated and leave some stuff on the end of it.";

// Fox...
echo truncate($s1, 30, "...");
// Lorem ipsum...
echo truncate($s2, 30, "...");
// Other one
echo truncate($s3, 40, "...");

      



Outputs:

The quick...the lazy dog
Lorem ipsum...ei duo.
This is some...on the end of it.

      

Note that the last bit is a ei duo

little shorter. This is because the total string returned is wordwrap()

not related to the total length. This could be handled, if it matters to you, by checking the strlen()

last element from the array $segments

and, if it is less than some threshold (say $len / 2

), split the array element before it into words with explode()

and add another word from that array.

Here's an improved version, addressing this issue, going back to the second line from wordwrap()

and popping words to the end is at least half the length $total_length

. This is a little more difficult, but has a more satisfying result. http://codepad.viper-7.com/mDmlL0

function truncate($string, $total_length, $separator) {
  // The wordwrap length is half the total, minus the separator length
    $len = (int)($total_length - strlen($separator)) / 2;

  // Separate the output from wordwrap() into an array of lines
  $segments = explode("\n", wordwrap($string, $len));

  // Last element length is less than half $len, append words from the second-last element
  $end = end($segments);

  // Add words from the second-last line until the end is at least
  // half as long as $total_length  
  if (strlen($end) <= $total_length / 2 && count($segments) > 2) {
    $prev = explode(' ', prev($segments));
    while (strlen($end) <= $total_length / 2) {
      $end = array_pop($prev) . ' ' . $end;
    }
  }

  // Return the first, separator, last
  return reset($segments) . $separator . $end;
}

// Produces:
The quick...over the lazy dog
Lorem ipsum...Alia oratio ei duo.
This is some other...stuff on the end of it.

      

+2


source







All Articles