Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Surprise: scalar(($x, $y) = split)

by ambrus (Abbot)
on Oct 28, 2011 at 13:53 UTC ( [id://934401]=perlmeditation: print w/replies, xml ) Need Help??

I was trying to read a text file each of whose lines should contain two whitespace-separated fields. I wrote the file so I know it has two fields per line, but it's better to be cautious, so I decided to check that it's indeed two fields. I wrote this.

while (<>) { 2 == (my($x, $y) = split " ") or die "wrong number of fields"; ... }
That gives the error
wrong number of fields at -e line 1, <> line 1.
despite that line 1 of the file really has exactly two fields. Why? Solution under the fold.

Replies are listed 'Best First'.
Re: Surprise: scalar(($x, $y) = split)
by JavaFan (Canon) on Oct 28, 2011 at 14:55 UTC
    $ perl -e 'warn 0+(@x = split " ", "foo bar\n");' 2 at -e line 1. $ perl -e 'warn 0+(($x, $y) = split " ", "foo bar\n");' 3 at -e line 1. $
    Note that there are *three* magical features happening. First there's the magic of the first argument; if the first argument of split is a pattern consisting of a single space, split splits on any whitespace. Which includes the newline. So, you actually have *3* fields, ("foo", "bar", "" -- the empty string following the newline), so it's the first case that's odd, not the second. It's the second magical feature that's to blame - in the absence of a limit, trailing empty fields are removed.

    You wouldn't have been surprised if you had chomped your line.

      The other two magic might be confusing but they're not really necessary here. I can still write this and be surprised.

      $ perl -we '$n = () = split ",", "one,two,three,four,five"; print "I f +ound $n comma-separated words\n"' I found 1 comma-separated words $ perl -we '$n = ($x) = split ",", "one,two,three,four,five"; print "I + found $n comma-separated words, the first of which is $x\n"' I found 2 comma-separated words, the first of which is one

      And even if I chomp the line, there could be trailing spaces or carriage returns in the line that I expect split " " to cut off.

      Adding to the confusion?

      $ perl -e 'warn 0+(($x, $y) = split/ /, "foo bar\n");' 2 at -e line 1. $ perl -e 'warn 0+(($x, $y) = split$", "foo bar\n");' 2 at -e line 1.
Re: Surprise: scalar(($x, $y) = split)
by roboticus (Chancellor) on Oct 28, 2011 at 14:03 UTC

    Update: Everything below is wrong, as ambrus mentions in the reply. (Note to self: Self, just because you get the correct result doesn't mean that you got the right answer!)

    ambrus:

    You forgot some parenthesis:

    (2==(my($x,$y) = split " ")) or die "wrong number of fieldsd";

    Example:

    $ cat foo.pl use strict; use warnings; my $x; my $y; while (<DATA>) { chomp; (2==0+(($x, $y) = split /:/,$_)) or print "wrong number of fields\ +n"; print "<$_>, <$x>, <$y>\n"; } __DATA__ FOO:BAR:BAZ:PLOVE FOO:BAR:BAZ FOO:BAR BAZ $ perl foo.pl wrong number of fields <FOO:BAR:BAZ:PLOVE>, <FOO>, <BAR> wrong number of fields <FOO:BAR:BAZ>, <FOO>, <BAR> <FOO:BAR>, <FOO>, <BAR> wrong number of fields Use of uninitialized value $y in concatenation (.) or string at foo.pl + line 7, <DATA> line 4. <BAZ>, <BAZ>, <>

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

        ambrus:

        Ha, ha--color me surprised as well!

        Corrected example:

        $ cat foo.pl use strict; use warnings; my $x; my $y; while (<DATA>) { chomp; 2==(($x, $y) = split " ") or print "wrong number of fields\n"; print "<$_>, <$x>, <$y>\n"; } __DATA__ FOO BAR BAZ PLOVE FOO BAR BAZ FOO BAR BAZ $ perl foo.pl wrong number of fields <FOO BAR BAZ PLOVE>, <FOO>, <BAR> wrong number of fields <FOO BAR BAZ>, <FOO>, <BAR> <FOO BAR>, <FOO>, <BAR> wrong number of fields Use of uninitialized value $y in concatenation (.) or string at foo.pl + line 7, <DATA> line 4. <BAZ>, <BAZ>, <>

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

Re: Surprise: scalar(($x, $y) = split)
by Fox (Pilgrim) on Oct 28, 2011 at 18:17 UTC
    Not so pretty.. but anyway:
    $ perl -wle '(my($x,$y) = @{[]} = split/ /,"foo bar") == 2 or die "boo +";warn "[$x] [$y]"' [foo] [bar] at -e line 1. $ perl -wle '(my($x,$y) = @{[]} = split/ /,"foo bar baz") == 2 or die +"boo";warn "[$x] [$y]"' boo at -e line 1.
Re: Surprise: scalar(($x, $y) = split)
by Anonymous Monk on Oct 29, 2011 at 08:19 UTC
    use strict; use warnings; { my( $x , $y ) ; print 'scalar( ($x, $y ) ) ', scalar( ($x, $y ) ) +, "\n"; print 'scalar( ($x, $y ) ) = () ', scalar( ($x, $y ) = + () ), "\n"; print 'scalar( ($x, $y ) ) = (undef) ', scalar( ($x, $y ) = + (undef) ), "\n"; print 'scalar( ($x, $y ) ) = (undef,undef) ', scalar( ($x, $y ) = + (undef,undef) ), "\n"; print 'scalar( ($x, $y ) ) = (0) ', scalar( ($x, $y ) = + (0) ), "\n"; print 'scalar( ($x, $y ) ) = (0,0) ', scalar( ($x, $y ) = + (0,0) ), "\n"; print 'scalar( ($x, $y ) ) = (1,0) ', scalar( ($x, $y ) = + (1,0) ), "\n"; print 'scalar( ($x, $y ) ) = (1,1) ', scalar( ($x, $y ) = + (1,1) ), "\n"; print 'scalar( ($x, $y ) ) = (1,1,1) ', scalar( ($x, $y ) = + (1,1,1) ), "\n"; print "\n\n"; } __END__ Useless use of private variable in void context at - line 5. Use of uninitialized value $y in print at - line 5. scalar( ($x, $y ) ) scalar( ($x, $y ) ) = () 0 scalar( ($x, $y ) ) = (undef) 1 scalar( ($x, $y ) ) = (undef,undef) 2 scalar( ($x, $y ) ) = (0) 1 scalar( ($x, $y ) ) = (0,0) 2 scalar( ($x, $y ) ) = (1,0) 2 scalar( ($x, $y ) ) = (1,1) 2 scalar( ($x, $y ) ) = (1,1,1) 3

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://934401]
Approved by moritz
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (2)
As of 2024-04-20 04:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found