Enhanced truncation of strings

Asked

Viewed 194 times

1

I was going over some old codes when I found a function that "truncates" a given string after X characters:

This function, unlike a replace() simple, does not leave the developer in awkward situations like this:

$str = 'Então, Chapeuzinho Vermelho decide tomar no cantinho, bem escondida, uma lata de leite condensado.';

var_dump( substr( $str, 45 ) . '...' );

That would result in:

So, Little Red Riding Hood decides to take...

Gets boring... :p

Already with this enhanced function, a statement like this:

var_dump( truncate( $str, 45, 'after' ) );

Would result in:

So Red Riding Hood decides to take it in the corner,...

Much better :D

However, I found two minor problems regarding the third scenario covered by the function, which adds the ellipsis in the middle of the string, thus:

So, Little Red Riding Hood ... little place, well hidden, a can of condensed milk.

The first of these is that, as seen in the above example, the ellipsis (or other character/substring configured) are not added near the middle of the string as it should.

The second problem is only noticeable with a few specific, often short strings, like this:

$str = 'Eu coloquei meu cabo de enxada no seu curral';

var_dump( truncate( $str, 35, 'center' ) );

That would produce:

I put my cable ... your corral

I mean, the words n of in his has been unduly deleted.

I even managed to solve this problem by subtracting 1 (one) from strlen( $append ) of $end.

But while it solves for small sentences, it corrupts for long sentences, causing the example of Little Red Riding Hood to result in:

So, Little Red Riding Hood....

That is, with an extra space after the string is inserted (before corner) in what would be the almost middle of the string (replaced by hashes to be visible).

It’s a silly problem of offset, but I couldn’t solve it the right way.

For the time being, a workaround was to replace any double spaces in the string before returning, but if possible fix rather than remedy, better.

Any idea?

2 answers

1

A solution, but I don’t think it’s very efficient, but functional:

function trucar($texto, $qtdCaracteres) {
    $string = strip_tags($texto);
    if (strlen($texto) > $qtdCaracteres) {
        while (substr($text, $qtdCaracteres, 1) <> ' ' && ($qtdCaracteres < strlen($texto))){
            $qtdCaracteres++;
        };
    };
    return substr($texto,0,$qtdCaracteres) . '...';
}

In this case we are looking for a space after the given interval, so only cut the string when there is a space.

And the use:

$texto = "Teste de escrita de texto.";

echo trucar($texto, 15);

The result will be: Writing test...

Source: http://www.sergiotoledo.com.br/tutoriais/programacao-php/criando-resumo-em-php

  • Your solution adds the reticence at the end of the string and fortunately I already have this. I’m looking for one that shortens the string as close as possible to the desired size, but place the ellipsis in the middle of the string, resulting in a bit of the beginning of the string, the ellipsis and then a bit of the end of it (see last example)

0


Well, I took the case pro Soen and I got a fantastic answer that not only solves the problem but, at my request, solves it in a balanced way.

That is, besides interpolating a configurable string between two substrings closest to the middle of the original string, does not break the words in the middle and still makes the resulting string to be quite close to that desired:

/**
 * Truncates a string at specified length without breaking words
 *
 * @param string $string
 *  The string to truncate
 *
 * @param integer $length
 *  The expected length after truncated
 *
 * @param string|optional $delimiter
 *  The string interpolated in the middle of string
 *
 * @return string
 *  Truncated string
 */
public static function truncate( $string, $length, $delimiter = '(...)' ) {

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

    $delimiter = sprintf( ' %s ', trim( $delimiter ) );

    $len = (int) ( ( $length - strlen( $delimiter ) ) / 2 );

    // Separate the output from wordwrap() into an array of lines

    $segments = explode( "\n", wordwrap( $string, $len ) ) ;

    /**
     * Last element's 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 $length
     */
    if( strlen( $end ) <= ( $length / 2 ) && count( $segments ) > 2 ) {

        $prev = explode( ' ', prev( $segments ) );

        while( strlen( $end ) <= ( $length / 2 ) ) {
            $end = sprintf( '%s %s', array_pop( $prev ), $end );
        }
    }

    return reset( $segments ) . $delimiter . trim( $end );
}

No wonder the guy has 141k of reputation :p

Browser other questions tagged

You are not signed in. Login or sign up in order to post.