in reply to Splitting in while loop

#!/usr/bin/perl use strict; use warnings; while (split(/[, ]+/, <DATA>)) { chomp; print "'$_'\n"; } __DATA__ me@here.com those@there.com others@there.com you@there.com,them@there.com

Outputs:

Use of uninitialized value $_ in scalar chomp at ./pm11137286.pl line +8, <DATA> line 1. Use of uninitialized value $_ in concatenation (.) or string at ./pm11 +137286.pl line 9, <DATA> line 1. '' Use of uninitialized value $_ in scalar chomp at ./pm11137286.pl line +8, <DATA> line 2. Use of uninitialized value $_ in concatenation (.) or string at ./pm11 +137286.pl line 9, <DATA> line 2. '' Use of uninitialized value $_ in scalar chomp at ./pm11137286.pl line +8, <DATA> line 3. Use of uninitialized value $_ in concatenation (.) or string at ./pm11 +137286.pl line 9, <DATA> line 3. '' Use of uninitialized value in split at ./pm11137286.pl line 9, <DATA> +line 3.

You probably want:

#!/usr/bin/perl use strict; use warnings; for (map { split /[, ]+/ } <DATA>) { chomp; print "'$_'\n"; } __DATA__ me@here.com those@there.com others@there.com you@there.com,them@there.com

Replies are listed 'Best First'.
Re^2: Splitting in while loop
by tel2 (Pilgrim) on Oct 07, 2021 at 05:16 UTC
    Nice work, thanks for both your solutions, tybalt89!

    Do you understand why mine wasn't working?

      G'day tel2,

      "... why mine wasn't working?"

      I believe you're working on the erroneous assumption that split(/[, ]+/, <DATA>) will assign its result to $_. That assignment to $_ only occurs in a select number of cases. From "perlsyn: Compound Statements":

      "If the condition expression of a while statement is based on any of a group of iterative expression types then it gets some magic treatment. The affected iterative expression types are readline, the <FILEHANDLE> input operator, ... If the condition expression is one of these expression types, then the value yielded by the iterative operator will be implicitly assigned to $_."

      For each of your while iterations, the condition is true three times, once for each DATA line; however, $_ is not set for any of those iterations. On the fourth iteration, there are no more DATA lines and the loop ends.

      Always add

      use strict; use warnings;

      to the top of your code. In this instance, although it wouldn't give a detailed explanation of the problem as I've provided, it would have hinted at a starting point for investigating the issue.

      — Ken

        Thanks for all that, Ken.

        I tried adding strict & warnings before opening this question, and I got the errors, but I just didn't realise what was going on, but I understand now.  Maybe I should have posted it with strict & warnings included, and asked why I'm getting the errors.

      Further to jwkrahn's post:   tel2: Note that implicit split to @_ has been deprecated for a long time:

      Win8 Strawberry 5.8.9.5 (32) Thu 10/07/2021 3:29:50 C:\@Work\Perl\monks >perl -Mstrict -Mwarnings my $data = <<'EOD'; me@here.com those@there.com others@there.com you@there.com,them@there.com EOD open my $fh, '<', \$data or die "opening: $!"; while (split(/[, ]+/, <$fh>)) { chomp @_; print "'$_'\n" for @_; } ^Z Use of implicit split to @_ is deprecated at - line 14. 'me@here.com' 'those@there.com' 'others@there.com' 'you@there.com' 'them@there.com'


      Give a man a fish:  <%-{-{-{-<

      while (split(/[, ]+/, <DATA>)) { ... }

      Only a while-loop condition expression like

      while (<DATA>) { ... }
      assigns implicitly to $_ (see tybalt89's example) (update: but see kcott's post for a more complete discussion of $_ assignment special-casing). An arbitrary expression like split(...) does not. Had you had warnings enabled, Perl would have at least hinted at this problem.


      Give a man a fish:  <%-{-{-{-<

      while (split(/[, ]+/, <DATA>))

      Is interpreted by perl as:

      while ( @_ = split( /[, ]+/, <DATA> ) )
        Thanks jwkrahn, but if they're interpreted to be the same, then why does this code:
        while (split(/[, ]+/, <DATA>)) { print @_ }
        print nothing, while this code:
        #while (split(/[, ]+/, <DATA>)) # Edit: Sorry - ignore this while (@_ = split(/[, ]+/, <DATA>)) # Edit: I meant this { print @_ }
        prints:
        me@here.com those@there.comothers@there.com you@there.comthem@there.com
        ?

        Update: Cancel the above.  I see AnomalousMonk's answer to it now.