views:

202

answers:

4

I am reading $digit from infile and want to print it to outfile. But the Perl script is giving an error saying 'Global symbol "$digit" requires explicit package name'. But, if I do declare it globally , $digit='', then the this value is printed to the outfile instead of the value extracted/read from infile. Any suggestions as to what should be done?

This how I am doing it:

    my $digit=''; 
    open (DATA, "</usr/infile") || die "cant open infile\n"; #file from digit has to read

    while (<DATA>){
        ($digit)= $_=~ /\s9\s(\d+)/; #regex to capture digit '234' from ' 9 234'
        if ($digit ne ""){
        print "digit is $digit\n"; # this prints fine
        }
    }

    open (FILE, ">/usr/outfile") || die "cant open outfile\n"; #file to which digit has to be finally written
    print FILE "9   $digit"; #$digit takes in the value declared globally i.e. ''

    close(DATA);
    close (FILE);
+2  A: 

Your $digit is scoped within the while loop and then you are trying to access it outside it with the line:

print FILE "9   $digit";

You must declare it outside the while loop for this to be visible by that line.

Or better yet just open your outfile before you loop and write the digit to the outfile within the loop and keep your $digit variable scoped within the loop.

If you only want the last instance that matches your regex then:

#!/usr/bin/perl
use strict;

open (DATA, "infile.txt")  || die("cant open infile\n");   

my $digit = "";
while (<DATA>) {
    chomp;
    if (/\s9\s(\d+)/) #regex to capture digit '234' from ' 9 234' 
    {
       print "Found digit is $1\n"; # 
       $digit = $1;
    }
}
close(DATA);

if ($digit ne "") {
open (FILE, ">outfile.txt") || die("cant open outfile\n"); 
print FILE "9   $digit\n";
close(FILE);
}
else
{
    print "No digit found!\n";
}
exit;

If you want to get all instances in the infile where your regex matches, the following should do the trick.

#!/usr/bin/perl
use strict;

open (DATA, "</usr/infile")  || die("cant open infile\n");   
open (FILE, ">/usr/outfile") || die("cant open outfile\n"); 

while (<DATA>) {
    chomp;
    if (/\s9\s(\d+)/) #regex to capture digit '234' from ' 9 234' 
    {
       print "Found digit is $1\n"; # 
       print FILE "9   $1\n";
    }
}


close(DATA);
close (FILE);
exit;
RC
@RC: as I said if I do declare it outside then it takes in that value (i.e. the value with which it was declared) and not the value being captured using regex. So what you are suggesting wont work.
shubster
The reason it isn't being captured when you declare it outside is b/c the my $digit; inside your while loop is the one being assigned by the regex, not the global one. Since the $digit inside the while goes out of scope at the while closing brace, you end up writing to outfile using the global $digit value instead of the one you set in the loop.
RC
@RC: So is there a way to write $digit to outfile with value it gets captures using regex?
shubster
sure....I'll put the code in my answer
RC
@RC: thanks! that works perfectly.
shubster
+1  A: 

Don't declare $digit with my inside your while() loop; declare it just outside:

my $digit;
while( <DATA> ) {
    # stuff that sets $digit... 
}

open( FILE , '>out' );
print FILE $digit;
genehack
Furthermore, don't use `my ($digit)` inside the loop because that declares *another* variable called `$digit`.
Greg Hewgill
Right, once you've declared `$digit` *once* with `my`, don't declare it again, just use it. @RC, what you're saying happens will happen if you use `my` more than once -- the variable inside the `while` is getting shadowed.
genehack
@genehack: As I mentioned, on doing that the '$digit' bring written to 'out' takes in the value with which it was declared i.e '' and not the one which is captured using regex.
shubster
@shubster post the revised code that you say isn't working then -- at this point there are 3 people (me, Greg, and RC) all telling you the exact same thing, so if you're going to claim it's not working, *show* what you're doing that isn't working -- because from what you've said so far, what all three of us has said is, um, right.
genehack
@genehack: I have updated the code.
shubster
great, now remove the 'my' from the first line of the `while()` loop, so that it reads: while (<DATA>) { ($digit) = $_ =~ /blahregexp/;and see if that doesn't work better. (Chas is right, however, in that $digit may still get stomped on by other lines; RC is right that you should probably just output $digit from inside the loop.)
genehack
@genehack: it does not work. If you know a way to retain the value outside the loop, let me know.
shubster
Can you show some sample data where the code fails?
genehack
A: 

You have declared $digits to be local to the scope of the while loop by using my. The $digit in the print statement is out of scope and that is what is causing the message.

To correct this, declare my $digit before the while loop or declare it with our instead of my to make it global.

I would do the following:

use strict;
use warnings;

my $digit = "None";  # None if there are no digits found

open (DATA, "</usr/infile") || die "cant open infile\n"; #file from digit has to read
while (<DATA>){    
    ($digit) = $_=~ /\s9\s(\d+)/; #regex to capture digit " 9 234"    
    if ($digit ne ""){    
        print "digit is $digit\n"; # this prints fine    
    }
}
open (FILE, ">/usr/outfile") || die "cant open outfile\n"; #file to which digit has to be finally written
print FILE "9   $digit";
close(DATA);
close(FILE);

If you did not get a digit, you would get None for the $digit.

Hope this helps.

Glenn
+2  A: 
while (<DATA>){
    my ($digit)= $_=~ /\s9\s(\d+)/; #regex to capture digit '234' from ' 9 234'
    if ($digit ne ""){
    print "digit is $digit\n"; # this prints fine
    }
}

Lexical variables (the ones created with my) exist within the scope they are declared, so $digit is created and destroyed each time through the loop.

Chas. Owens
@Chas.Owens: So is there any other way to write $digit to another file?
shubster