http://www.perlmonks.org?node_id=375486


in reply to In search of a better way to trim string

sub trimTo { my( $str, $n ) = @_; return $str if length $str < $n; substr( $str, 0, 1 + rindex( $str, ' ', $n-3 ) || $n-3 ) . '...'; }

Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon

Replies are listed 'Best First'.
Re^2: In search of a better way to trim string length
by kiat (Vicar) on Jul 19, 2004 at 08:57 UTC
    Thanks, BrowserUk!

    Very cool code but harder to understand for me...I ran it and got the results as expected, with a tiny 'bug'. When I passed it the string "this is a very long sentence without spaces in between", the shortened string was "this is a very long ..." (no problem there).

    When I passed it the string "thisisaverylongsentencewithoutspacesinbetween", the output was "thisisaverylongsentencewith..." i.e. without any space between the last character of that string and '...'.

    Nothing serious really but just thought I would bring it up.

      Maybe a little explanation will help?

      sub trimTo { my( $str, $n ) = @_; ## Give back what they gave us if the nothing to do return $str if length $str < $n; my $lastSpace = 1 + rindex( $str, ' ', $n-3 ); ## Subtracting 3 allows for adding the '...' ## rindex finds the last space preceding the position ## or -1 if it fails. ## Adding 1 means that we can test whether it found the space +with ## if( 1+rindex...) { ... ## or supply a default value ## 1 + rindex( ... ) || $default ## It also means that we get a length that we can supply ## directly to substr without having to increment it. substr( $str, 0, $lastSpace || $n-3 ) . '...'; ## The substr( ... ) returns from the start of string ## to the first space before the postition-3 (including that space +) ## or the first $n characters of the string. ## Combining the two avoids a temporary var. ## Tack on the '...' }

      With respect to the 'bug'. I actually consider the difference a bonus in as much as "stuff ..." indicates that there are more words that were truncated.

      Whereas "stuff..." indicates that the word itself was truncated.

      If you prefer the other behaviour, then this will do it.

      sub trimTo { my( $str, $n ) = @_; return $str if length $str < $n; my $lastSpace = 1 + rindex( $str, ' ', $n-3 ); ## Truncate length allowing to always include the ' ' before '. +..' my $truncLen = ( $lastSpace || $n-3 ) - 1 ; return substr( $str, 0, $truncLen ) . ' ...'; }

      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algoritm, algorithm on the code side." - tachyon

        This is cool but it suffers from a problem that the first one I wrote did too. Give it:

        my $mouse = 'This is a story about mice, "I dint know mice were so sma +rt."'; print trimTo($mouse,30), "\n";

        And you can get back things like: This is a story about mice,... The comma (or semi-color, period, quote, etc) is a bit jarring.

        This is a recent stab I've ended up using but I would love to see other ideas/answers/hybrids:

        sub chop_to_size { my ($text, $length) = @_; return $text if length $text < $length; # make room for ellipsis my $chop = $length - 3; $text =~ s/^\s*(.{$chop})\s*.+$/$1/; $text =~ s/[\s[:punct:]]+$//; $text .= "..."; $text; }
        That was a great help! Thanks :)