Text::Wrap::Smart - Wrap text into chunks of (mostly) equal length


Text-Wrap-Smart documentation Contained in the Text-Wrap-Smart distribution.

Index


Code Index:

NAME

Top

Text::Wrap::Smart - Wrap text into chunks of (mostly) equal length

SYNOPSIS

Top

 use Text::Wrap::Smart qw(wrap_smart);

 $text = "..."; # random length

 # example options
 %options = (
             no_split => 1,
             max_msg_size => 160,
            );

 @chunks = wrap_smart($text, \%options);

DESCRIPTION

Top

Text::Wrap::Smart was primarly developed to split an overly long SMS message into chunks of mostly equal size. The distribution's wrap_smart() may nevertheless be suitable for other purposes.

FUNCTIONS

Top

wrap_smart

 @chunks = wrap_smart($text [, { options } ]);

options may contain the no_split option indicating that words shall not be broken up which indicates 'fuzzy wrapping` (if no_split is undefined, 'exact wrapping` will be applied). max_msg_size sets the character length boundary for each chunk emitted.

SEE ALSO

Top

Text::Wrap

AUTHOR

Top

Steven Schubiger <schubiger@cpan.org>

LICENSE

Top

This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html


Text-Wrap-Smart documentation Contained in the Text-Wrap-Smart distribution.

package Text::Wrap::Smart;

use strict;
use warnings;
use base qw(Exporter);

use Carp qw(croak);
use Math::BigFloat;

our ($VERSION, @EXPORT_OK);

$VERSION = '0.6';
@EXPORT_OK = qw(wrap_smart);

sub wrap_smart
{
    my ($text, $conf) = @_;
    croak "wrap_smart(\\\$text [, { options } ])\n" unless defined $text;

    my $msg_size = $conf->{max_msg_size} || 160;
    my $no_split = $conf->{no_split};

    my $exact_split = !$no_split;

    my $i;
    my $length = length $text;
    my $length_eval = $length;

    do {
        $length_eval -= $msg_size;
        $i++;
    } while ($length_eval > 0);

    my $x = Math::BigFloat->new($length / $i);
    my $average = $x->bceil;

    if ($exact_split) {
        return _exact_wrap($text, $conf, $average)
    }
    else {
        return _fuzzy_wrap($text, $conf, $average);
    }
}

sub _exact_wrap
{
    my ($text, $conf, $average) = @_;

    my (@chunks, $pos);
    my $length = length $text;

    for ($pos = 0; $pos < $length; $pos += $average) {
        my $chunk = substr($text, $pos, $average);
        push @chunks, $chunk;
    }

    return @chunks;
}

sub _fuzzy_wrap
{
    my ($text, $conf, $average) = @_;

    my (@chunks, $have_space, $pos);
    my $msg_size = $conf->{max_msg_size} || 160;

    my $offset = 0;
    my $text_eval = $text;

    while ($offset < length($text) - 1) {
        if (length $text_eval > $average && $text_eval =~ / /) {
            $pos = rindex($text_eval, ' ', $average);
            $have_space = 1;
        }
        else {
            $pos = $have_space ? length $text_eval : $msg_size;
        }

        $pos = length $text_eval if $pos == -1;
        my $chunk = substr($text_eval, 0, $pos);
        $pos++;
        my $length = 0;

        if ($pos > length $text_eval) {
            $pos = length $text_eval;
            $length = 0;
        }
        else {
            $length = length($text_eval) - $pos;
        }

        $text_eval = substr($text_eval, $pos, $length);
        $offset += $pos;

        local $/ = ' ';
        chomp $chunk;

        push @chunks, $chunk;
    }

    return @chunks;
}

1;
__END__