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

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.