How can I pad part of a string with spaces, in Perl?

27,488

Solution 1

I don't like option 2 as it introduces an unnecessary special case.

I would refactor out the construction of the prompt suffix:

    # Possible at top of program
    my $suffix =  ( ' ' x $p ) . $prompt;

    # Later...

    $key .= $suffix ;

Solution 2

I would prefer

sprintf "%-7s : %s", $key, $value;

or

sprintf "%-*s : %s", $p, $key, $value;

instead of all this weird stuff.

From sprintf documentation:

The flag characters

'-' The converted value is to be left adjusted on the field boundary. (The default is right justification.) The converted value is padded on the right with blanks, rather than on the left with blanks or zeros. A '-' overrides a 0 if both are given.

The field width

An optional decimal digit string (with nonzero first digit) specifying a minimum field width. If the converted value has fewer characters than the field width, it will be padded with spaces on the left (or right, if the left-adjustment flag has been given). Instead of a decimal digit string one may write '*' or '*m$' (for some decimal integer m) to specify that the field width is given in the next argument, or in the m-th argument, respectively, which must be of type int. A negative field width is taken as a '-' flag followed by a positive field width. In no case does a nonexistent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the field is expanded to contain the conversion result.

Solution 3

Call me old-school, but I'd use printf() or sprintf():

printf "%-33s%s%s\n", $key, $prompt, $value;

That left justifies the string $key into 33 spaces, adds $prompt and $value and a newline. If I wanted to calculate the length for the first part dynamically:

printf "%-*s%s%s\n", $len, $key, $prompt, $value;

Since it is one line instead of the question's 4 (option 1) or 6 (option 2), it scores favourably on the succinctness scale.

Solution 4

I looks a little weird, but this works (until now):

#!/usr/bin/env perl
use warnings; use strict;
use 5.010;
use utf8;
use Term::Size;
my $columns = ( Term::Size::chars *STDOUT{IO} )[0];
binmode STDOUT, ':encoding(UTF-8)';
use Text::Wrap;
use Term::ANSIColor;

sub my_print {
    my( $key, $value, $prompt, $color, $p ) = @_;
    my $length = length $key.$prompt;
    $p -= $length;
    my $suff = ( ' ' x $p ) . $prompt;
    $key .=  $suff;
    $length = length $key;
    my $col = $columns - $length;
    $Text::Wrap::columns = $col;
    my @array = split /\n/, wrap ( '','', $value ) ;
    $array[0] = colored( $key, $color ) . $array[0];
    for my $idx ( 1..$#array ) {
    $array[$idx] = ( ' ' x $length ) . $array[$idx];
    }
    say for @array;
}

my $prompt = ' : ';
my $color = 'magenta';
my $p = 30;
my $key = 'very important text';
my $value = 'text ' x 40;

my_print( $key, $value, $prompt, $color, $p );
Share:
27,488
sid_com
Author by

sid_com

Updated on August 16, 2020

Comments

  • sid_com
    sid_com almost 4 years

    Which version would you prefer?

    #!/usr/bin/env perl
    use warnings; 
    use strict;
    use 5.010;
    
    my $p = 7; # 33
    my $prompt = ' : ';
    my $key = 'very important text';
    my $value = 'Hello, World!';
    
    my $length = length $key . $prompt;
    $p -= $length; 
    

    Option 1:

    $key = $key . ' ' x $p . $prompt;
    

    Option 2:

    if ( $p > 0 ) { 
        $key = $key . ' ' x $p . $prompt;
    }
    else {
        $key = $key . $prompt;
    }
    

    say "$key$value"