in reply to Re: In place search and replace with a hash
in thread In place search and replace with a hash

I think I understand your editing a file instructions, and if so I was really over-complicating things trying to do an "in place" replacement. Now I am trying something like this:
open FH, "<infile.txt" or die $!; open OUT, ">outfile.txt"; while (<FH>) { if (/(\S+):(\S+).*\n/) { $var1 = "$1"; $var2 = "$2"; print OUT "$var1_$var2\n" } elsif (/(.*)\n/) { print OUT "$1\n"; } } close FH;

This does what I want in terms of preserving the input files non matching lines, but I am still getting a "use of uninitialized value" error, one for every line in the input file:

Use of uninitialized value $var1_ in concatenation (.) or string at test_perl.pl line 42

Replies are listed 'Best First'.
Re^3: In place search and replace with a hash
by AnomalousMonk (Archbishop) on Dec 28, 2014 at 04:29 UTC
    print OUT "$var1_$var2\n"

    The  '_' (underscore) character is a valid identifier, i.e., variable name, symbol. Therefore, the two variables you're using are  $var1_ (note trailing _), which is not defined, and  $var2, which is. Had you been using strictures as well as warnings, Perl would not have allowed this little oversight (see strict and warnings). The proper way to write this statement (if you really need the _) is
        print OUT "${var1}_$var2\n";
    (Note that I've added a ; at the end; the absence of this statement terminator caused no syntactic problem in the given code, but would have eventually — trust me.)

    open FH, "<infile.txt" or die $!;
    open OUT, ">outfile.txt";

    Update: You seem to be back-sliding. In contrast to your OPed code, this code uses global filehandles, two-parameter open, and does not check the status of the output file open. Tsk, tsk! IMHO, the OPed code used better practices.


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

      Ah, thank you! I don't know why I was trying to use "_". Totally unnecessary. Now that you have helped me to fix most of these basic problems, I am back to the original problem of replacing the hash keys with the hash values. The hash is created with:
      use strict; use warnings; open my $fh, '<', 'hash_test.txt' or die "Cant open file $!"; LINE: while (my $line = <$fh>) { my ($key, $value) = split /\s/, $line; next LINE if not $key; $hash{$key} = $value; chomp (%hash); while ( my( $key, $value ) = each %hash ) } close $fh;

      Then the hash keys are searched for (and replaced with their associated values if found) in the input file using

      open FH, "<infile.txt" or die $!; open OUT, ">outfile.txt"; while (<FH>) { if (/(\S+):(\S+).*\n/) { $var1 = "$1"; $var2 = "$2"; print OUT "$hash{$var1} $var2\n"; } elsif (/(.*)\n/) { print OUT "$1\n"; } } close FH;

      This results in the error

      Use of uninitialized value within %hash in concatenation (.) or string at test_perl.pl line 41, <FH> line 5

      UPDATE I think the problem was that I had initialized my %hash inside a while loop. I moved it up to the beginning of the program, and it worked!

        ... back to the original problem of replacing the hash keys with the hash values.

        You say you know your translation hash is being built properly, so since I'm about to turn into a pumpkin, let me leave you with the following code to think about:

        Play with it and get the substitutions right, and you can move on to the business of writing the edited file tomorrow.


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

      Thanks Anomalous, I see what you mean by backsliding- I had been testing the code with a single file to control for errors with the loop (and avoid being overwhelmed by error messages). Here is the updated code that works. I see other responses suggesting better ways to do this and potential problems with the hash, and I will address those as well. But at the moment, this works. Thanks for all your help!

      #!/usr/bin/perl use strict; use warnings; my %hash = (); open my $fh, '<', 'sample_name_ID_hash.txt' or die "Cant open file $!" +; LINE: while (my $line = <$fh>) { my ($key, $value) = split /\s/, $line; next LINE if not $key; $hash{$key} = $value; chomp (%hash); } close $fh; @file_array = <*.nex> or die $!; #find all the files foreach $file (@file_array) { my $prefix = $file; $prefix =~ s/\.nex//; open FH, "$file", or die $!; print "found $file with prefix $prefix\n"; open OUT, ">out$prefix.nex" or die $!; while (<FH>) { if (/^\s+\'(\S+):(\S\d+)\|\w+\|(\d)\S+\'(.*)\n/) { $var1 = "$1"; $var2 = "$2"; $var3 = "$3"; $var4 = "$4"; print OUT "'$hash{$var1}_${var2}_$var3'$var4\n"; } elsif (/(.*)\n/) { print OUT "$1\n"; } } }
Re^3: In place search and replace with a hash
by AnomalousMonk (Archbishop) on Dec 28, 2014 at 05:02 UTC
    if (/(\S+):(\S+).*\n/) { $var1 = "$1"; $var2 = "$2"; print OUT "$var1_$var2\n" } elsif (/(.*)\n/) { print OUT "$1\n"; } }

    Ok, once you get that working (i.e., fix  $var1_ problem), try reducing the big if-statement to a single  s/// substitution (untested):
        s{ (\S) : (\S) }{${1}_$2}xmsg;
    (which just replaces every : with an _), followed by a print of the (possibly altered) line (held in  $_ in this code) to the output filehandle.

    Update: This reply may have been superseded by your intervening post, but what the heck...


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