Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

How to grep for a filename for each of the keys of a hash

by perl_mystery (Beadle)
on Dec 13, 2010 at 04:01 UTC ( [id://876785]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, I have the following two simple questions.I wrote the following ,need your input if there is a better way.

1.I want to grep for a variable $filename for all the keys in a hash "path_versions",

grep (/$filename/i, $key) foreach my $key (keys %path_versions)

2.I have the below line in a variable "$depopath" where parts of it are seperated by spaces,I want to get only the part after the last space.In this case just "Z:\repo\bin\tools\scripts\shared\users\script.pl"

+//depot/asic/tools/scripts/shared/users/script.pl //cspec/tools/scripts/shared/users/script.pl Z:\repo\bin\tools\scripts\shared\users\script.pl

my $match = $depopath =~ /\s(.:.+?)/

Replies are listed 'Best First'.
Re: How to grep for a filename for each of the keys of a hash
by graff (Chancellor) on Dec 13, 2010 at 06:01 UTC
    I want to grep for a variable $filename for all the keys in a hash "path_versions",

    Normally, that sort of description goes with this sort of code:

    my @matches = grep /$filename/, keys %path_versions;
    If you meant something different from what that does, you need to give us a better description of what you are trying to do. (I seem to say that sort of thing a lot when responding to your posts... Have you noticed?)

    As for your usage of grep in the OP, it seems like you haven't looked at the documentation for the grep function in perl. Try this command line, and read the output that it produces.

    perldoc -f grep
    You can do the same for any other perl function that you're unsure about. (I use this command almost every day to look things up and check out how functions are supposed to be used. When I was first learning Perl, I used it about every 20 minutes on average.)

    ... I want to get only the part after the last space...

    my $last_string = ( split /\s+/, $depopath )[-1];
    The parens around the split call create an array, and the [-1] at the end takes the last element of the array.
      When I was first learning Perl, I used it about every 20 minutes...

      I've 'learned' Perl, and I still use it about every 20 minutes.

Re: How to grep for a filename for each of the keys of a hash
by Anonymous Monk on Dec 13, 2010 at 04:19 UTC
    $filename is not a regular expression, use eq

    The metacharacter . will match a space

    Space, followed by notSpace, at the end of the string, ie /\s(\S+)$/ or /\s(\S+)\z/

    or with substr/rindex

    $ perl -le"my $f = q!a b c d ee!; print substr $f, 1+rindex $f, q! !" ee
Re: How to grep for a filename for each of the keys of a hash
by ELISHEVA (Prior) on Dec 13, 2010 at 09:31 UTC

    Even with the \Q...\E your regular expression may not be doing what you want.

    $filename='Z:\repo\bin\tools\scripts\shared\users\script.pl'; $key =~ /\Q$filename\E/i; #matches (notice different starts and ends) Z:\repo\bin\tools\scripts\shared\users\script.pl Z:\repo\bin\tools\scripts\shared\users\script.plm Z:\repo\bin\tools\scripts\shared\users\script.plx Z:\repo\bin\tools\scripts\shared\users\script.pl\foobar \\?\Z:\repo\bin\tools\scripts\shared\users\script.plm # and does NOT match Z:/repo/bin/tools/scripts/shared/users/script.pl

    The extra matches come because /\Q$filename\E can match anywhere within a string, not just beginning to end. To match the whole string you need to start with a caret and end with a dollar sign: /^\Q$filename\E$/. However if you are matching the whole string and using quotemeta (\Q...\E) you might as well just do lc $key $eq lc $filename. lc makes both sides of the equality lower case, making case irrelevant just as the i flag on the regex does.

    The missed matches come from the MS-Windows operating systems having several different ways of expressing the exact same path. Making your regex case insensitive may not be enough to get all the matches you want.

    I forget exactly when MS started recognizing '/' in paths, but certainly XP onward, you can use either '/' or '\' to separate path segments. One solution to that is to preprocess your paths by substituting '\' for '/', e.g. grep { lc $_ eq lc $filename } map { s/\//\\/g; $_ } @paths or grep { my $x=$_;$x =~ s/\//\\/g; lc $x eq lc $filename } @paths if you want to preserve the original paths in your output array.

    Update: added alternative that preserves original paths.

Re: How to grep for a filename for each of the keys of a hash
by AnomalousMonk (Archbishop) on Dec 13, 2010 at 09:08 UTC
    grep (/$filename/i, $key) foreach my $key (keys %path_versions)

    FYI, this form of statement modifier is syntactically incorrect (in addition to doing nothing with the output of grep if the statement was modified so it could compile). See Statement Modifiers in perlsyn.

    Specifically, a  for loop statement modifier cannot use a named loop variable, but instead uses the implicitly localized (or 'topicalized') default scalar $_. E.g.:

    >perl -wMstrict -le "my @words = qw(foo bar baz); print qq{'$_'} foreach @words; " 'foo' 'bar' 'baz'
Re: How to grep for a filename for each of the keys of a hash
by Anonymous Monk on Dec 13, 2010 at 04:47 UTC
    1: $filename is presumably a string, not a pattern, which you want to match; so you have to escape metacharacters first if you're going to use it in a regular expression: /\Q$filename\E/, for example, if you don't want to modify that variable with the quotemeta function or don't need the quoted version for anything else ($foo = quotemeta $foo; or my $foo_quoted = quotemeta $foo;</code>).

    2:

    • my ($foo) = $depopath =~ /\s(\S+)$/;
    • or my ($foo) = reverse split ' ', $depopath;

      As per above comments you use the quotemeta function.
      And
      Insist of the below code

      grep (/$filename/i, $key) foreach my $key (keys %path_versions)

      You will try the below code. Here, you no need to use the foreach loop. You directly pass 'hash keys'.

      @array = grep (/$filename/, keys %path_versions);
        push @array = grep (/\Q$file_name\E/i, keys %pathname_versions);

        I am getting the below error when the above piece of code is executed,what does it mean?

        Type of arg 1 to push must be array (not list assignment)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2024-04-23 15:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found