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

I need to have a fixed length for the string I manipulate.
For e.g. if the word is 'someword' and I want it to be of fixed length 5, then script should strip the extra 3 (5-length of word i.e. 8) characters and give me the word - 'somew'.
Whereas if the fixed length is to be 10 (10 - length of word i.e. 8), then script should add 2 spaces to the word i.e. 'someword##'.
# - denotes the blank space.

Replies are listed 'Best First'.
Re: fixed length string
by edan (Curate) on Jul 05, 2004 at 09:45 UTC
Re: fixed length string
by muntfish (Chaplain) on Jul 05, 2004 at 09:44 UTC

    Perl doesn't have a data type with that behaviour, but you could try something like:

    use strict; my ($len, $str) = (5, "someword"); $str = sprintf "%-${len}.${len}s", $str; print ">>$str<<\n";
    s^^unp(;75N=&9I<V@`ack(u,^;s|\(.+\`|"$`$'\"$&\"\)"|ee;/m.+h/&&print$&;
Re: fixed length string
by BrowserUk (Patriarch) on Jul 05, 2004 at 10:46 UTC

    YAW.

    print "'", pack( 'A5', $_ ), "'" for qw[ so some somewhat ]; 'so ' 'some ' 'somew'

    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
      Pack truncates as well as pads. (Mental note: caffeinate before posting.)

      Rate srchrep xprintf YAW srchrep 5434/s -- -79% -82% xprintf 25870/s 376% -- -16% YAW 30876/s 468% 19% --
Re: fixed length string
by keszler (Priest) on Jul 05, 2004 at 10:05 UTC
    s/// can do the job: use .{1,$x} to get the first 1 to $x characters, discarding any after $x, then pack "A$x" to space-pad to $x.
    #!perl use strict; my $fixlen = 5; my @words = qw( s so som some somew somewo somewor someword somewords) +; foreach my $word (@words) { $word =~ s/^(.{1,$fixlen}).*$/pack "A$fixlen", $1/e; print ">$word<\n"; } __END__ >s < >so < >som < >some < >somew< >somew< >somew< >somew< >somew<
      I was curious, so I compared the two one-liners (s/// and sprintf), as follows:

      #!perl use strict; use Benchmark qw( timethese cmpthese ) ; my $fixlen = 5; my @words = qw( s so som some somew somewo somewor someword somewords) +; my $b = timethese( -5, { srchrep => sub{foreach my $word (@words) { $word =~ s/^(.{1,$fixlen}).*$/pack "A$fixlen", $1/e +; }}, xprintf => sub{foreach my $word (@words) { $word = sprintf "%-$fixlen.${fixlen}s", $word; }}, }); cmpthese $b; __END__ Benchmark: running srchrep, xprintf for at least 5 CPU seconds... srchrep: 5 wallclock secs ( 5.54 usr + 0.00 sys = 5.54 CPU) @ 54 +48.01/s (n=30182) xprintf: 6 wallclock secs ( 6.76 usr + 0.00 sys = 6.76 CPU) @ 20 +874.11/s (n=141109) Rate srchrep xprintf srchrep 5448/s -- -74% xprintf 20874/s 283% --
      Looks like sprintf wins the speed test, by a large margin.
      my @words = qw( s so som some somew somewo somewor someword somewords) +;

      Just a tip for the lazy...

      my $str = 'somewords'; local ($\,$,) = ("\n") x 2; print map {substr $str, 0, $_} 1..length($str); # or print map {$str =~ /(.{$_})/} 1..length($str); # or { my $mem; print map {$mem .= $_} split //, $str; } # etc. (Golf?)
Re: fixed length string
by gellyfish (Monsignor) on Jul 05, 2004 at 13:44 UTC

    As has been pointed out perl does not natively have a fixed length datatype - but it is easy to do something that make a scalar behave like that:

    FixedLength.pm:

    package FixedLength; use strict; use warnings; sub TIESCALAR { my ( $class, $length) = @_; my $self = {}; $self->{_item} = undef; $self->{_length} = $length; return bless \$self, $class; } sub FETCH { my ($self) = @_; return $$self->{_item}; } sub STORE { my ( $self, $value ) = @_; my $len = $$self->{_length}; $$self->{_item} = pack "A$len", $value; } 1;

    Test Code:

    use FixedLength; use strict; my $foo; tie $foo, 'FixedLength', 5; my @words = qw( s so som some somew somewo somewor someword somewords) +; foreach my $word ( @words) { $foo = $word; print "*$foo*\n"; }

    /J\

Re: fixed length string
by borisz (Canon) on Jul 05, 2004 at 09:49 UTC
    You can use substr to get parts of your string and the x operator to add missing parts.
    my $max = 10; my $string = 'something'; $string = substr($string, 0, $max); my $length = length $string; $string .= ' ' x ( $max - $length ) if ( $length < $max );
    Boris
Re: fixed length string
by Crian (Curate) on Jul 05, 2004 at 09:43 UTC
    You could use a function like this:

    #!/usr/bin/perl use strict; use warnings; sub cut_fill ($$); my $word = 'someword'; print "'", cut_fill($word, 5), "'\n"; print "'", cut_fill($word, 10), "'\n"; sub cut_fill ($$) { my ($word, $length) = @_; if (length($word) >= $length) { $word = substr($word, 0, $length); } else { $word .= ' 'x($length - length($word)); } return $word; }
    Update: Or you can use sprintf of corse, as shown in the solutions below. But if you need something more special, a function like this will be handy.
Re: fixed length string
by gmpassos (Priest) on Jul 06, 2004 at 07:02 UTC
    How about one line, ops, one command?! ;-P
    $s = sprintf("%-5.5s" , $s) ;

    Graciliano M. P.
    "Creativity is the expression of the liberty".