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

Hi I am looking for some help advice on a program I have been wrting for the past few days. What I would like to do is look through a list of filenames that I have already made up, I split the lines on a dot, and for the first part of the line that I call base if it is of the form rrv193 then 4 digits then cm then I rename that $base. Here is a piece of test code to show how I am attemting to do this, but the hash bit doesnt work. Is it because of the expression or becasue you cant do this in a hash? or have I got the wrong end of the stick
#!/usr/bin/perl #my hash which tries to "map" a regular expression to a a new name my %Ren2Dol = ( rrv193\d{4}cm => "RNF191", ); #pretend data line to teest my $line='rrv1931009cm.new090626'; #split the data line ($base,$rest)=split(/[\.\_]/,$line,2); #test print it to see that it split correxctly print "$base\n"; #try to see what new name would be my $newname=$Ren2Dol{$base}; print "$newname\n"; # a test print to make sure regular expression matches if ($line=~m/^rrv193\d{4}cm/) {print "line matched\n"}; if ($base=~m/^rrv193\d{4}cm/) {print "base matched\n"};

Replies are listed 'Best First'.
Re: regular expression in a hash
by GrandFather (Saint) on Jul 08, 2009 at 09:39 UTC

    It doesn't do what you are thinking. Not that I can figure out what you are thinking quite, but I'm quite sure it doesn't do it.

    For a start rrv193\d{4}cm => "RNF191", is a syntax error. Possibly you want 'rrv193\d{4}cm' => "RNF191", which at least compiles, but my guess is that you are heading at the problem from the wrong direction. I suspect you are hoping that the hash key in some magical fashion will behave as a regular expression and will "match" any string provided as a "key" that it matches on. Sorry, it don't work that way.

    So, what are you really trying to do. Not the solution you've come up with, but the bigger problem you are trying to solve?

    My guess is you have a number of these matches and you want to provide a different replacement string for each one. So lets run with that idea for a moment. Consider:

    use strict; use warnings; my %Ren2Dol = ( 'rrv193\d{4}cm' => "RNF191", 'rrv194\d{4}cm' => "RNF196", 'rrv195\d{4}cm' => "RNF200", ); while (<DATA>) { chomp; my ($base, $rest) = split /[\.\_]/, $_, 2; my ($match) = grep {$base =~ /$_/} keys %Ren2Dol; if (defined $match) { print "$Ren2Dol{$match}\n"; } else { print "$base\n"; } } __DATA__ rrv1931009cm.new090626 rrv1941009cm.new090626 rrv1951009cm.new090626 rrv1961009cm.new090626 rrv1931234cm.new090626

    Prints:

    RNF191 RNF196 RNF200 rrv1961009cm RNF191

    True laziness is hard work
      If you regular expressions as your keys, then you save the overhead of recompiling them everytime. The qr// operator does this for you.
      my %Ren2Dol = ( qr(rrv193\d{4}cm) => "RNF191", qr(rrv194\d{4}cm) => "RNF196", qr(rrv195\d{4}cm) => "RNF200", );

      Here's your code with tests. This does the actual search/replace as necessary as it converts @data to @output.

      use strict; use warnings; use Test::More tests=>1; use Data::Dumper; my %Ren2Dol = ( qr(rrv193\d{4}cm) => "RNF191", qr(rrv194\d{4}cm) => "RNF196", qr(rrv195\d{4}cm) => "RNF200", ); my @data = qw( rrv1931009cm.new090626 rrv1941009cm.new090626 rrv1951009cm.new090626 rrv1961009cm.new090626 rrv1931234cm.new090626 ); my @expected = qw( RNF191.new090626 RNF196.new090626 RNF200.new090626 rrv1961009cm.new090626 RNF191.new090626 ); my @output; foreach (@data) { while( my( $regex, $replace ) = each (%Ren2Dol)) { s/$regex/$replace/ex; } push @output, $_; } is_deeply( \@expected, \@output, "names updated correctly") or diag( Dumper{ expected=>\@expected, got=>\@output });
      Hi Grandfather your prediction as to what I was trying to achieve was absolutely perfect. I have now go the remainder of the script I have been trying for a couple of weeks to solve Thanks to you and everyone else who has made suggestions David
Re: regular expression in a hash
by fullermd (Vicar) on Jul 08, 2009 at 09:30 UTC
    my %Ren2Dol = ( rrv193\d{4}cm => "RNF191", );

    Having 'special' bits in there will keep autoquoting from work. Try manually quoting the key.

    'rrv193\d{4}cm' => "RNF191",

    (that may not be the problem you're hitting, but it's certainly a problem)

Re: regular expression in a hash
by BioLion (Curate) on Jul 08, 2009 at 09:43 UTC

    Your 'pattern' is not being strored as a pattern but as a literal string.
    So

    my $newname=$Ren2Dol{$base};
    is not doing a pattern match, but just a lookup

    Then you would need to iterate through your patterns and reassign the name on success.

    use strict; use warnings; my $string = '^a{4}b{2}'; my $patt = qr/$string/; my %hsh = ($string => $string, $patt => $patt,); my $test = 'aaaabb'; foreach (keys %hsh){ print "YES for regex : $_\n" if $test =~ /$_/; } print "YES for existance : $_\n" if (exists$hsh{$test});

    see qr// and perlre for how to compile a string into a pattern.

    Hope this helps!

    Just a something something...
Re: regular expression in a hash
by Anonymous Monk on Jul 08, 2009 at 09:21 UTC
    Backslash found where operator expected at 2 line 2, near "rrv193\" syntax error at 2 line 2, near "rrv193\" Execution of 2 aborted due to compilation errors.