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

Dear Monks,

Why does this bit of code give me problems?

$infile = "outfile.txt"; open (INFILE, "$infile"); $out_b = "outfile_b.txt"; open (OUT_B, "+>>$out_b"); while(<INFILE>){ print "here\n"; if ($_ =~ /^(.{1,50})\t{0,50}(.{0,50})\t{0,1}(.{0,50})\t{0,1}(.{0, +50})\t{0,1}(.{0,50})\t{0,1}(.{0,50})/){ print "here_B\n"; $gene_id = $1; if ($2 = /.{1,50}/){ (@alternative_ids, $2)}; if ($3 = /.{1,50}/){ (@alternative_ids, $3)}; if ($4 = /.{1,50}/){ (@alternative_ids, $4)}; if ($5 = /.{1,50}/){ (@alternative_ids, $5)}; if ($6 = /.{1,50}/){ (@alternative_ids, $6)}; if ($7 = /.{1,50}/){ (@alternative_ids, $7)}; if ($8 = /.{1,50}/){ (@alternative_ids, $8)}; if ($9 = /.{1,50}/){ (@alternative_ids, $9)}; print @alternative_id; foreach (@alternative_ids){ $alternative_id = $_; print OUT_B "$gene_id\t$alternative_id\n"; } undef @alternative_ids; } }
where infile is something like:
YAL069W YAL069W Yal069wp YAL068C YAL068C Yal068cp SEO1 YAL067C SEO1 Seo1p YAL066W YAL066W Yal066wp YAL065C YAL064W-B YAL064W-B Yal064w-bp YAL064C-A YAL064C-A Yal064c-ap YAL064W
I get the error message:
Modification of a read-only value attempted at extract_notes_B.pl line + 149, <INFILE> line 2.

Replies are listed 'Best First'.
Re: File handle problems
by PodMaster (Abbot) on Jun 24, 2003 at 10:05 UTC
    Consider this
    #!/usr/bin/perl -w use strict; ( $2, $66 ) = ( 1, 2 ); __END__ Modification of a read-only value attempted at - line 4.
    Then read `perldoc perlvar' and `perldoc perlre' to see why $N is special.

    Also, error checking++ open FOO, $bar or die "whooops $!";

    Also, you may wish to use diagnostics as it gives more wordy error messages, like:

    Modification of a read-only value attempted at - line 4 (#1) (F) You tried, directly or indirectly, to change the value of a constant. You didn't, of course, try "2 = 1", because the compile +r catches that. But an easy way to do the same thing is: sub mod { $_[0] = 1 } mod(2); Another way is to assign to a substr() that's off the end of the s +tring. Yet another way is to assign to a foreach loop VAR when VAR is aliased to a constant in the look LIST: $x = 1; foreach my $n ($x, 2) { $n *= 2; # modifies the $x, but fails on attempt to mo +dify the 2 } Uncaught exception from user code: Modification of a read-only value attempted at - line 4.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

Re: File handle problems
by gellyfish (Monsignor) on Jun 24, 2003 at 10:06 UTC

    it is the lines starting with:

    if ($2 = /.{1,50}/){ (@alternative_ids, $2)};
    You have used the assignment rather than the binding operator =~

    /J\
    
Re: File handle problems
by broquaint (Abbot) on Jun 24, 2003 at 10:07 UTC
    The problem is that you can't can't assign to the number variables e.g
    shell> perl -e '$1 = "bang"' Modification of a read-only value attempted at -e line 1.
    I'm guessing you mean to do a match instead using the =~ operator. See. the perlop and perlre for more info on the matching operator and the number variables.
    HTH

    _________
    broquaint

Re: File handle problems
by Jasper (Chaplain) on Jun 24, 2003 at 11:27 UTC
    As well as the = instead of =~ problem that other people have already addressed, what are you doing with the values in the captures?

    { (@alternative_ids, $8)}

    doesn't do anything, as far as I'm aware. You might want to be pushing (perldoc -f push) values onto that array.

    Also, you have one use of @alternative_id, when all the rest are @alternative_ids. You could look into the use of use strict; to avoid this sort of typo.

    edit: Another thing is that for $2, $3 etc. you already know that they match /.{0,50}/, since that's how you grabbed them from the original regex. To subsequently check them with /.{1,50}/ is (to me) a bit of overkill. You could just use either if $2 (or $2 =~ /./ if $2 is allowed to be '0')

    edit:Another thing to note, and one that's very important (it just occurred to me when I was thinking of something else) is that if you have $1, $2, $3 etc, and then run another match, they will all get wiped out. So as soon as you do:

    if ($2 = /.{1,50}/){ (@alternative_ids, $2)};

    all your subsequent tests (and whatever you were wanting to do with $2 in that block) are to no avail. $3, $4, $5 etc. simply aren't there any more. You'll have to assign them to slightly more persistent variables beofre running any matching tests on them.

    Jasper
Re: File handle problems
by Jasper (Chaplain) on Jun 25, 2003 at 13:51 UTC
    Right. Apologies for answering this again, but I've reread the priginal post, and what I think you actually want is:
    my ($gene_id, @alternative_ids) = split; All the rest is just confusing. This replaces from your  if ($_ =~ match down to your  if ($9 ... line.

    I hope that's helped this time.

    Jasper - sure no one is listening anymore.