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

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

Hello Monks,
when I want to split a string, I do this:
my ($x, $y, $z) = split(',', $_); print "x = $x y= $y z =$z\n";
but if there are not enough tokens, then I get the following warning
Use of uninitialized value in concatenation (.) or string at ... (second line)
Is it possible to initialize the variables to nill - if they are not defined in the same line?
Thanks

Replies are listed 'Best First'.
Re: split and uninitialized variables
by jeffa (Bishop) on Sep 03, 2004 at 15:26 UTC

    I prefer to store the list returned by split in an array or hash slice:

    use strict; use warnings; use Data::Dumper; my @key = qw(x y z); my %hash; while (<DATA>) { chomp; @hash{@key} = split ','; print Dumper \%hash; } __DATA__ a,b,c a,b a,b,c,d a,,,

    [UPDATE] No. Scalars are not the better choice simply because you know what the data that you are working on looks like. If you deal with multiple things, why not put them in a container so you only have to move one thing around? :)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      That is what I usually do. But if you know what the data you are working on, then scalars will be better.
      One example could be "name, address-line1, address-line2"
      and line 2 might be or might not be present.
      So to summarise the replies, it would be better to initialize them in the next line.
      All the other solutions seem to have some problems!

        The ( '' ) x 3 solution doesn't.

        Another option:

        my ( $foo, $bar, $baz ); $_ .= '' for ( $foo, $bar, $baz ) = split /,/;

        Makeshifts last the longest.

Re: split and uninitialized variables
by Eimi Metamorphoumai (Deacon) on Sep 03, 2004 at 15:05 UTC
    I'm sure there are a lot of ways to do that, but I'd probably go with
    my ($x, $y, $z) = (split(',', $_), '' x 3);
    which does the split, but also puts empty strings onto the end of the list. Then your variables grab the first three items from the list, running into the empty strings if they run out of data from the split.

    Update: ambrus is right. That's what I get for testing code without warnings on.

      This won't work, as '' x 3 is just ''. Instead,

      my ($x, $y, $z) = (split(',', $_), ('') x 3);
      will work.
      This solution is novel and works, but I don't recommend it.

      . It's more important to have code that is clear and easy to read than to be as concise and compact as possible. The clearest solution is to simply use a second line to initialize the variables.

        I'm aware of the importance of clarity. If I were golfing I would have done something like
        my ($x, $y, $z) = split(',', "$_,,");
        but this was the most natural answer to me. The problem, as I saw it, was "sometimes the list returned by split is too short, and I want empty strings to fill missing places at the end," so the most natural answer I saw was to add items to fill it out.
Re: split and uninitialized variables
by Arunbear (Prior) on Sep 03, 2004 at 15:08 UTC
    You can do
    my ($x, $y, $z) = ('', '', ''); ($x, $y, $z) = split(',', $_);
    OR
    my ($x, $y, $z) = map { $_ || '' } split(',', $_);
    to ensure the variables are initialised.

    Update: Oops! I really need a new brain.

    use strict; use warnings; $_ = "a,0,b"; my ($x, $y, $z) = split(',', $_); foreach ($x, $y, $z) { $_ = '' unless defined($_) } print "x = $x\ny = $y\nz = $z\n"; __END__ x = a y = 0 z = b

      Your first solution

      my ($x, $y, $z) = ('', '', ''); ($x, $y, $z) = split(',', $_);

      won't work. Any values assigned in the first line will get overwritten in the second line:

      $_ = 'a,b'; my ($x, $y, $z) = ('', '', ''); ($x, $y, $z) = split(',', $_); print(defined($z)?'defined':'undefined', "\n"); # prints undefined.

      Your second solution

      my ($x, $y, $z) = map { $_ || '' } split(',', $_);

      erases any '0'. Try:

      my ($x, $y, $z) = map { defined($_)?$_:'' } (split(',', $_))[0..2];

      Personally, I'd go with the simple my ($x, $y, $z) = (split(',', $_), ('') x 3); solution mentioned elsewhere.

      Update: Added missing [0..2] as pointed out by Roy Johnson. Thanks.

        Actually, the map solution doesn't work, because split doesn't return three elements, so you'd need to make it
        my ($x, $y, $z) = map { defined($_) ? $_ : '' } (split(/,/, $_))[0..2] +;

        Caution: Contents may have been coded under pressure.

      Your first one's not going to work.

      main::(-e:1): 0 DB<1> $_ = "a,b" DB<2> x ($x,$y,$z) = ('default') x 3 0 'default' 1 'default' 2 'default' DB<3> x ($x,$y,$z) = split( ',', $_ ) 0 'a' 1 'b' 2 undef

      Both methods have problems:

      > perl -wl my ($x,$y,$z) = ('','',''); ($x,$y,$z) = split(',','a,b'); print "$x $y $z"; __END__ Use of uninitialized value in concatenation (.) or string at - line 3. a b > perl -wl my ($x, $y, $z) = map { $_ || '' } split(',', 'a,0,b'); print "$x $y $z"; __END__ a b

      The second one is easily fixed with:

      perl -wl my ($x, $y, $z) = map defined $_ ? $_ : '', (split(',', 'a,0,b'))[0..2 +]; print "$x $y $z"; __END__ a 0 b

      Update: Doh! Thanks !1 (silly lurker).

      antirice    
      The first rule of Perl club is - use Perl
      The
      ith rule of Perl club is - follow rule i - 1 for i > 1

Re: split and uninitialized variables
by ccn (Vicar) on Sep 03, 2004 at 16:00 UTC
    my ($x, $y, $z) = map { defined() ? $_ : '[undef]' } split ',', $_, 3; print "x = $x y= $y z =$z\n";
A reply falls below the community's threshold of quality. You may see it by logging in.