artist has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perlmonks

I am looking for ways to fully justify the text, given the number of lines. Thus text should be left justified and right justified. The number of spaces should be adjusted accordingly in such a way I don't see 'big' gaps between words. So I am looking for something similar as Text::Format, but more as I supply the number of lines.
Example:

I like this site which help me to learn perl more
Number of lines: 2
Number of columns:26
I  like  this  site  which
help me to learn perl more
Thank you for your insight.
Practicing Justifying Art,
Artist

Replies are listed 'Best First'.
Re: Text Formatting
by theorbtwo (Prior) on Dec 22, 2002 at 04:26 UTC

    A simple search.cpan.org search for text justify gives several good hits, including Text::WrapProp and Text::Format.

    Update: Yeah, reading the entire original post before replying is a good thing. Try setting all margin/indent properties to 0 characters, then setting the line length to length($instr)/$number_lines.


    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

      Hi,

      I tried that, and here is my code.

      use Text::Format; my $in_string = q(It should be clear to any frequent air passenger tha +t in order to reach one city from another, the cost of the shorter fl +ight may be more than the cost of longer flights. In other words, it +may pay you well to cool your heels in an airport waiting for a conne +cting flight rather than take a more direct flight or one in which th +e connecting time is shorter. For example, consider the following fli +ght schedule.); $text = Text::Format->new({ text => [$in_string], columns => 50, justify => 1, firstIndent => 0, } ); print $text->format;
      Problems from my perspective with this code:
      1. I cannot say that I want this text to be spreaded in 10 lines and 90 columns. Because I like to supply the line numbers rather than calculate it.

      2. The last line is not properly right-justified. It leaves all the spaces after the last word.

      3. Justification should come at entire paragraph level and not just at 'line' level. So it's ok to have 2 or more spaces between the words if required, as long as entire paragraph is justfied within given 'box' of columns and lines as long as I don't see 'big' gaps between words.

      Thanks,
      Artist

        This is not clever but it might be of some help if you are completely stuck. Caution : It doesn't work if the space available for the text is too small.
        use strict; use warnings; my $in_string = q(It should be clear to any frequent air passenger that in order to reach one city from another the cost of + the shorter flight may be more than the cost of longer flights. In other words, it may pay you well to cool your heels in an airport w +aiting for a connecting flight rather than take a more direct flight or one in which the connecting time is shorter. For + example, consider the following flight schedule.); # # Work out how many spaces are needed in the text in total and divide +by # the number of lines to get an approximate number of spaces per line. + # Break the text into lines on total word lengths assuming this number + # of spaces is added to each line. # Recalculate the break points after each line. # my $NO_OF_LINES = 12; my $CHAR_PER_LINE = 45; # check it is not impossible if ( length($in_string) > ($NO_OF_LINES * $CHAR_PER_LINE) ){ die "Can' +t be done\n" }; # split into words and calculate total characters my @words = split /\s/,$in_string; my $total_chars = 0; for (@words){ $total_chars += length($_); ; } # how many spaces must there be in the text my $spaces_to_add = ( $NO_OF_LINES * $CHAR_PER_LINE ) - $total_chars; # initialize my $line=""; my $lines_left = $NO_OF_LINES; my $space_avail = $CHAR_PER_LINE - int ( $spaces_to_add / $lines_left +) ; # process for my $w (@words){ my $w_length = length($w); if ( $w_length == $space_avail ){ $line .= $w; $w = ""; } else { if ( $w_length < $space_avail ){ $line .= "$w "; $space_avail -= $w_length; --$spaces_to_add; next; } } # reduce by those that will be added when justified $spaces_to_add -= ( $CHAR_PER_LINE - length($line) ); # print the result print &justify_line($line)."|\n"; # recalculate space_available for characters for the next lines --$lines_left; if ($lines_left > 1){ $space_avail = $CHAR_PER_LINE - int ( $spaces_to_add / $lines_le +ft ) ; } else { $space_avail = $CHAR_PER_LINE - $spaces_to_add ; } # prepare next line $line = $w; if ($w ne ""){ $line .= " "; --$spaces_to_add; $space_avail -= length($w); } } # # add spaces between words to justify a line # sub justify_line { my @words = split ' ',shift; my $spaces_left = $CHAR_PER_LINE; for (@words){$spaces_left -= length($_)}; my $new_line = $words[0]; # add equal space to each word for my $i (1..$#words){ # calc number a spaces per word my $no_of_spaces = int ($spaces_left / ($#words + 1 - $i)); $spaces_left -= $no_of_spaces; $new_line .= " " x $no_of_spaces . $words[$i]; } return $new_line; };
        poj