Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Testing for the presence of a hash key in a filename

by NovMonk (Chaplain)
on May 25, 2007 at 14:25 UTC ( [id://617499]=perlquestion: print w/replies, xml ) Need Help??

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

Esteemed Monks,

As I continue my journey towards enlightenment, I am finding myself wanting to try simpler but more unfamiliar ways of handling a task. Here's a simplified version my current task: could someone please tell me if this solution will work, or if I'm barking up the wrong tree?

I have a list of abbreviations that appear as part of a much longer filename, i.e. DNI,SNI,JRN, etc. Based on whether a particular combination appears anywhere in the filename, I have to call a corresponding color logo.

Where I might once have constructed a godawful succession of conditional statements, it occurred to me I might make a hash where that pattern to match is the key, and the call to the correct color logo is the value. But-- here my inexperience overwhelms me. It seems like I would still need a godawful set of conditionals to test for the presence of this key variable in the filename.

So, my question-- what would be the best way to handle or just think about this situation? At the least, I can write subroutines that check for the pattern match in the filename and do things accordingly. But it seems like there should be a cleaner way I haven't thought of.

Thanks for your time and patience.

Pax,
NovMonk

  • Comment on Testing for the presence of a hash key in a filename

Replies are listed 'Best First'.
Re: Testing for the presence of a hash key in a filename
by kyle (Abbot) on May 25, 2007 at 14:49 UTC
    sub do_dni { my ( $filename ) = @_; print "dni: $filename\n"; } sub do_sni { my ( $filename ) = @_; print "sni: $filename\n"; } my %dispatch = ( 'DNI' => \&do_dni, 'SNI' => \&do_sni, # etc. ); foreach my $fn ( @filenames ) { while ( my ( $pattern, $sub_ref ) = each %dispatch ) { $sub_ref->($fn) if ( $fn =~ /$pattern/ ); } }

    If you fear the regexes getting compiled over and over, you could also do something like this:

    my @dispatch = ( { pattern => qr/DNI/, coderef => \&do_dni, }, { pattern => qr/SNI/, coderef => \&do_sni, }, ); foreach my $fn ( @filenames ) { foreach my $item ( @dispatch ) { $item->{coderef}->($fn) if ( $fn =~ $item->{pattern} ); } }
      use Tie::RegexpHash; ## &do_dni and &do_sni ... as before my %dispatch; tie %dispatch, 'Tie::RegexpHash'; %dispatch = ( qr/DNI/ => \&do_dni, qr/SNI/ => \&do_sni, # etc. ); foreach my $fn ( @filenames ) { $dispatch{$fn}->{$fn} }

      citromatik

Re: Testing for the presence of a hash key in a filename
by Fletch (Bishop) on May 25, 2007 at 14:49 UTC

    One approach:

    • Make a hash with the keys being the abbreviations and the values the corresponding logo
    • Use Regexp::Assemble to build up a regular expression from the keys of your hash which will capture the abbreviation
    • Use that constructed regex against your filenames and then use $1 to key your hash lookup

    I'm presuming this is some sort of HTML output and it's something like the path to an image. If you actually needed to munge the filename in some way the vaules in the hash could be coderefs instead which implement whatever particular substitution or other mungery you need.

      It's basically what I'd do too. I'd just construct the regex myself I guess.
      Something along the lines of:
      my $match = '('.join( '|', sort keys %replace ).')'; and then use the value in $replace{$1}

      if( exists $aeons{strange} ){ die $death unless ( $death%2 ) }

        It appears from the problem description that the keys are all three characters, but just as a heads-up, you might want to add a reverse to that:

        my $match = '('.join('|', reverse sort keys %replace).')';

        The reverse ensures that the longest match is found even if some pattern is a prefix of another (which, in my experience, is generally the desired outcome). e.g.:

        #!/usr/bin/perl -l use strict; use warnings; my %replace = qw/pre 1 prefix 2/; my $norev = '('.join('|', sort keys %replace).')'; my $withrev = '('.join('|', reverse sort keys %replace).')'; while (<DATA>) { chomp; print "Line: $_"; print "norev <$1>" if /$norev/; print "w/rev <$1>" if /$withrev/; } __END__ This line contains prefix (which also matches 'pre')

        Should print:

        Line: This line contains prefix (which also matches 'pre') norev <pre> w/rev <prefix>
Re: Testing for the presence of a hash key in a filename
by blazar (Canon) on May 25, 2007 at 15:58 UTC
    I have a list of abbreviations that appear as part of a much longer filename, i.e. DNI,SNI,JRN, etc. Based on whether a particular combination appears anywhere in the filename, I have to call a corresponding color logo.

    In addition to what others suggested, I have a question: I suppose that the order in which the abbreviations appear does not matter. But, for example, must filenames wich have respectively only DNI and SNI, only SNI and JRN, and all of DNI, SNI and JRN be associated to different logos? If so, then I would build the keys in terms of sorted abbreviations (possibly uniq'd too), joined on some standard separator:

    my %logo = ( DNI => 'logo1', JRN => 'logo2', SNI => 'logo3', DNI_JRN => 'logo4', DNI_SNI => 'logo5', JRN_SNI => 'logo6', DNI_JRN_SNI => 'logo7', ); # ... print my $logo = $logo{ join '_', sort $name =~ /(DNI|JRN|SNI)/g };
Re: Testing for the presence of a hash key in a filename
by suaveant (Parson) on May 25, 2007 at 14:51 UTC
    my %list_of_keys = qw(DNI 1 SNI 1 JRN 1); my $filename = 'foo,JRN,SNI,bar'; my $regex = join('|', map { "\Q$_\E" } keys(%list_of_keys)); $regex = qr{\b($regex)\b}; # case insensitive? while($filename =~ /$regex/ig) { my $key = $1; print "Found key $key\n"; }
    Also look at Regex::PreSuf which builds a better regex from a list of words.

    Of course... if you always have a set delimeter you can do something like

    my @values = split ',', $filename; for(@values) { print "Found key $_\n" if $list_of_keys{$_}; }
    That is a better way to do it if you have something you can split on reliably

                    - Ant
                    - Some of my best work - (1 2 3)

Re: Testing for the presence of a hash key in a filename
by citromatik (Curate) on May 25, 2007 at 14:42 UTC

    Could you please put a simple example of what you want to do?

    It seems like Tie::Hash::Regex can do something with your problem, but I want to be sure I have understand it

    citromatik

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://617499]
Approved by kyle
Front-paged by naikonta
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-04-25 08:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found