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

if I have $test{qr/foo/} and $test{foo} how can I tell that one key is a compiled regex and one is a string?

Replies are listed 'Best First'.
Re: Compiled regex as hash key vs. string?
by ikegami (Patriarch) on Nov 11, 2006 at 08:14 UTC
    Actually, both keys are strings and neither key is a compiled regexp. A strinfigied copy of what is in the curlies is used as the key.
    use strict; use warnings; my %test; my $re = qr/foo/; my $s = 'foo'; print('re: ', ref($re) || 'Not Regexp', "\n"); print('s: ', ref($s ) || 'Not Regexp', "\n"); $test{$re} = 1; $test{$s } = 1; foreach (keys %test) { print("key $_: ", ref($_) || 'Not Regexp', "\n"); }
    outputs
    re: Regexp s: Not Regexp key (?-xism:foo): Not Regexp key foo: Not Regexp
Re: Compiled regex as hash key vs. string?
by davido (Cardinal) on Nov 11, 2006 at 08:09 UTC

    Have you looked at the output from qr/.../? It's a lot different than the output from single quotes.

    Try the following code, and you'll see what I mean:

    my %hash = ( qr/test/, 0, 'test' , 0, ); print "$_\n" foreach keys %hash;

    Dave

Re: Compiled regex as hash key vs. string?
by bart (Canon) on Nov 11, 2006 at 13:27 UTC
    n.b. blahblah and ikegami and me had a long conversation about his real problem on the chatterbox, earlier today, and we found several entirely different approaches to achieve what he really wants — ikegami even provided a complete alternative program. So, just for the annals, here's a little reply that is just taking the direction of his question here.

    I now know you want to distinguish between data matching one of two kinds of sources, it either equals this hash key string (if it's supposed to be treated as a string) or matches the regexp (if it represents a regexp) — the above hash is a kind of dispatch table, originally just matching literal strings, and now he has to extend it to match using a pattern — preferably in a backward compatible way. But you can't distinguish between strings and regexes in hash keys any more, since every hash key is nothing but a string.

    One approach I prosposed is to always use a regexp for the hash keys, converting strings to a regexp using quotemeta and string start/end anchors. That way you don't have to make the distinction. But that involves recompiling the regex every time you want to do a test. Not so good.

    So another approach is to have an extra caching hash, that maps these string keys to, well, whatever you like. I suggest you use something looking like globs on the left, because it's probably easier for maintenance, eventually converting them to the equivalent regexp by code — once.

    my %process = ( 'foo*' => qr/^foo.*$/, foo => 'foo' );
    Now you can make the distinction you asked about, in the values of this hash. And regexps remain Regexps.

    As a sample converter of glob to regexp, you can do something like this:

    { my %replace; sub glob_to_regexp { my $pattern = shift; %replace or %replace = ( '*' => '.*', '?' => '.' ); $pattern =~ s/(\W)/ $replace{$1} || quotemeta($1)/ge; return qr/^$pattern\z/; } }

    Of course, you can implement more advanced glob features if you like, patching the convertor code accordingly.

Re: Compiled regex as hash key vs. string?
by davidrw (Prior) on Nov 11, 2006 at 17:27 UTC
    not sure it's directly relevant, but i noticed Tie::Hash::Regex the other day and it came to mind..