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

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

Thanks very much for the feedback, everyone and sorry about any confusion, I hope my questions aren't trivial. I've 4 further questions on Revised Code Below, thanks very much in advance.

1. If I use $in on Lines 6 - 8 and print any elements, the entire lines of the file are returned without being processed (with pipes included). I thought I could substitute $_ with any variable. Why won't it work here?

2. If I use $_ on these lines instead, then I get good results (the specified element on Line 12.

3. If I UnComment Lines 9 - 11, a '1' is returned between the last 2 elements in each line. Why is that?

4. To clarify myself (on moritz's question), even-numbered elements return nothing, eg. if I type print $fields[0], "\r"; on line 12 in my revised script, I get nothing. I've found that any even number gives me nothing, it's odd, I thought the 0th element would be 'Baw', the 1st element would be 'Vao' and so on. The pipe is discarded by perl, so I don't understand why the even-numbered elements are 'skipped', so to print 'Baw', I type print $fields1, "\r" and to print 'Vao', I type print $fields3, "\r"

1 #!/usr/bin/perl -w 2 use strict; 3 4 open my $datfh, '<', 'C:\begperl\my scripts\cdata.txt' or die "Could +n't open file: $!\n"; 5 6 foreach my $_ (<$datfh>) { 7 my @fields = (map { s/^\s+//; s/\s+$//, $_ } # eliminates irr +elevant spaces 8 split /\|/, $_); 9 # for my $i (0 .. $#fields) { 10 # print $fields[$i], "\n" unless $fields[$i] =~ /\r|\n/; 11 # } 12 print $fields[1], "\r"; 13 } 14 close $datfh;

My File's data (for testing):

Baw|Vao|111 Noa St||NewYork|NY|10012|2123456789|123456789

Vca|Wxr|384 Mkl Ln|Xillo|Crrnt Stt|CT|05506|1015567781|1015567782

Uaa|Kvbr|805 Test Rd|Zero|This St|MN|17205|3018757203|3012986736

Caa|Lvbr|905 Test Rd|Bero|That St|MD|12705|3028887203|3028886736

Eaa|Pvbr|311 Zest Rd|Tero|My St|MI|12505|3018757203|3012986736

Replies are listed 'Best First'.
Re: reading array elements
by moritz (Cardinal) on Nov 26, 2008 at 08:57 UTC
    1. this script jumps to the 2nd line/record in the file instead of processing from the first line.
    Sure it does, because you read one line before the loop, in line 5 of your script. So the loop never sees the first line of cdata.txt
    2. Another issue is that accessing the elements using even numbers doesn't work, only odd numbers can be used to retrieve the elements, eg. when $i = 7

    Care to explain what "doesn't work" mean? Does a ninja attack you from behind every time you try? Or does your computer blow up?

    Please note that since you declared my $i inside the while loop, its value is reset in every iteration - probably not what you want. The special variable $. contains the line number of the input file handle, maybe that helps you.

    And what do you think the next is doing in line 15?

Re: reading array elements
by Erez (Priest) on Nov 26, 2008 at 10:07 UTC

    I'd like to know why lines 9 & 10 in my script have to have $_ instead of $in

    Because you wrote it that way?

    The idiom while (<FH>) implicitely assign each line read to $_. In essence, what you were probably aiming for is

    foreach my $in (<$datfh>)
    then use $in instead of $_ in your script. You also don't need next or last, unless you want to force flow control to act differently than it usually does, which brings me to:

    Instead of traversing left to right until end of line, then processing the next line until the end of the file; the script processes the ith element of each line only, bypassing the other elements of each line.

    No, it does exactly that, only you request it to pick only the 11th element (my $i = 11; then print $fields[$i]). If you want to print all the splitted parts of the line, just say print join "\n", @fields;

    "A core tenant of the greater Perl philosophy is to trust that the developer knows enough to solve the problem" - Jay Shirley, A case for Catalyst.

Re: reading array elements
by jonadab (Parson) on Nov 26, 2008 at 12:54 UTC

    I'm trying to figure out what you want this script to do, and I'm coming up blank. The best I can do for turning it into anything meaningful is as follows:

    open my $datfh, '<', 'C:\begperl\my scripts\cdata.txt' or die "Couldn' +t open file: $!\n"; while (<$datfh>) { print "**** Processing new input line\n"; my @fields = (map { s/^\s+//; s/\s+$//; # eliminate irrelevant spaces $_ } split /\|/, $_); for my $i (0 .. $#fields) { print " * '$fields[$i]'\n" unless $fields[$i] =~ /\r|\n/; } }

    This, of course, doesn't actually do anything. It just reads reads the file and tells you what it's reading, which you could have got just about as well by opening the file itself in a text editor and looking at it. But from just reading the information you gave us, I wasn't able to figure out what processing you wanted the script to do.

    -- 
    We're working on a six-year set of freely redistributable Vacation Bible School materials.

      Thanks very much for the feedback, everyone and sorry about any confusion, I hope my questions aren't trivial. I've 4 further questions on Revised Code Below, thanks very much in advance.

      1. If I use $in on Lines 6 - 8 and print any elements, the entire lines of the file are returned without being processed (with pipes included). I thought I could substitute $_ with any variable. Why won't it work here?

      2. If I use $_ on these lines instead, then I get good results (the specified element on Line 12.

      3. If I UnComment Lines 9 - 11, a '1' is returned between the last 2 elements in each line. Why is that?

      4. To clarify myself (on moritz's question), even-numbered elements return nothing, eg. if I type print $fields[0], "\r"; on line 12 in my revised script, I get nothing. I've found that any even number gives me nothing, it's odd, I thought the 0th element would be 'Baw', the 1st element would be 'Vao' and so on. The pipe is discarded by perl, so I don't understand why the even-numbered elements are 'skipped', so to print 'Baw', I type print $fields1, "\r" and to print 'Vao', I type print $fields3, "\r"

      1 #!/usr/bin/perl -w 2 use strict; 3 4 open my $datfh, '<', 'C:\begperl\my scripts\cdata.txt' or die "Could +n't open file: $!\n"; 5 6 foreach my $_ (<$datfh>) { 7 my @fields = (map { s/^\s+//; s/\s+$//, $_ } # eliminates irr +elevant spaces 8 split /\|/, $_); 9 # for my $i (0 .. $#fields) { 10 # print $fields[$i], "\n" unless $fields[$i] =~ /\r|\n/; 11 # } 12 print $fields[1], "\r"; 13 } 14 close $datfh;

        Hi, sorry it took me so long to get back to you on this; I had a couple of busy weeks and didn't look at Perlmonks. But anyway, in case you're still interested, I'll go ahead and answer now...

        If I use $in on Lines 6 - 8 and print any elements, the entire lines of the file are returned without being processed (with pipes included). I thought I could substitute $_ with any variable. Why won't it work here?

        $_ is magic, and sometimes refers to different things according to context. In particular, map assigns each of the things in the list to $_ in turn and uses the codeblock to transform them, so when you use $_ inside a map codeblock, it refers to one item in the list that you are mapping over. You can and should use a different variable outside the map (and, indeed, the code as you have it now won't compile because you tried to scope $_ lexically; changing it to $in fixes this), but inside the map codeblock the $_ has special meaning, and you need it there.

        If I UnComment Lines 9 - 11, a '1' is returned between the last 2 elements in each line. Why is that?

        Because one substitution was made. The substitution operator (s///) returns undef when there were no substitutions made, but otherwise it returns the number of substitutions performed. If you don't understand why the return value of the substitution operation is appearing in your output, you should maybe look at the syntax in your map operation more closely. You're returning a list of two things for each one thing in the input list. (If this is not what you want, you can return only the last item by changing the comma to a semicolon.)

        even-numbered elements return nothing

        If you change your data so that they include more trailing spaces, you'll get numbers there instead of nothing. But if you don't want those values at all, you can change the map operation as mentioned above.

        -- 
        We're working on a six-year set of freely redistributable Vacation Bible School materials.