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

Is there a way (module?) to create/access hash arrays where the keys are case-insensitive? So,

my %assoc = (); $assoc{'TheKey'} = "test"; print $assoc{'theKEY'} . "\n";
...would return "test".

thanks for any suggestions...
MFN

Replies are listed 'Best First'.
Re: case-insensitive hash keys
by BrowserUk (Patriarch) on Aug 21, 2004 at 00:44 UTC

    I thought there was a tie module for this but a quick scan of the first couple of hundred didn't find it. So here's one.

    As Limbic~Region point's out, I was looking in the wrong namespace. As well as Hash::Case::Preserve, there is also Hash::Case::Lower. The difference between the two (besides the obvious) is that the former uses two hashes internally. One for allowing the case-insensitive matching, the other for preserving the original case of the keys for when iterating with keys or each.

    The also showed me that I forgot a couple of bits below. (Now added.)

    #! perl -slw use strict; package Tie::Hashi; use Tie::Hash; our @ISA = 'Tie::ExtraHash'; sub TIEHASH{ bless [{}], $_[ 0 ]; } sub STORE { $_[ 0 ][ 0 ]{ lc $_[ 1 ] } = $_[ 2 ]; } sub FETCH { $_[ 0 ][ 0 ]{ lc $_[ 1 ] }; } sub EXISTS{ exists $_[ 0 ][ 0 ]{ lc $_[ 1 ] }; } sub DELETE{ delete $_[ 0 ][ 0 ]{ lc $_[ 1 ] }; } 1; package main; tie my %hashi, 'Tie::Hashi'; $hashi{ TheKey } = 12345; print $hashi{ tHeKeY }; print keys %hashi, $/, values %hashi; __END__ P:\test>tiehashi.pl 12345 thekey 12345

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: case-insensitive hash keys
by Zaxo (Archbishop) on Aug 21, 2004 at 00:14 UTC

    The simplest way is to just force every use to lower-case:

    my %assoc = (); $assoc{lc('TheKey')} = 'test'; print $assoc{lc('TheKEY')}, $/;

    (Added) Take a look at Hash::Case. It has Hash::Case::Lower, which uses a tied hash to enforce lower case keys. Sounds like just what you want.

    After Compline,
    Zaxo

      Good idea, but this would be as a modification to a set of Perl scripts that use hashes extensively, with approx. 20,000 lines of code. :S So, I guess I'm looking for something that doesn't require that much modification as inserting the lc() function everywhere.
        ManFromNeptune,
        Hash::Case::Preserve, in the same family as the module suggested by Zaxo, does case insensitive keys while maintaining the original case. The thing is you have to tie the hash using this module. There is no magic way to say "treat all hashes in this program as case insensitive".

        Cheers - L~R

        I have not thought this through completely, but you could use a tied hash which on STORE used a lowercase function. This would alleviate the need to have a lc() all over the code but it would slow your code down a bit. Again, this is off the top of my head so it might not work.

Re: case-insensitive hash keys
by qumsieh (Scribe) on Aug 21, 2004 at 05:25 UTC
    Well, if you really don't care about whether the keys remain in their original case or not, you can do something like this (untested):
    $assoc{lc $_} = delete $assoc{$_} for keys %assoc;
    This will convert all keys to lower case. Then to check, you make sure the key is lc()ed:
    print $assoc{lc 'theKEY'} . "\n";
    HTH.

      Maybe I'm missing something here, but it seems to me that this would be a good Perl intepreter flag... i.e., that all associate array keys should be treated case-insensitively. The interpreter would implicitly run "lc" when computing the hash value for storing or retrieving a value.

      The background here, as I alluded to above, is that I've got about 20,000 lines of code for a web system. Alot of my application is database-driven, and I have a module that just contains functions to retrieve rows from numerous tables.

      The mechanism for returning data from the retrieve functions is a pointer to a hash table (of the returned row). The keys in the hash are case-sensitive names of the fields. So the risk here is that someone who maintains this code makes a change and typos a hash key. Unlike with using strict vars, where Perl warns you if it thinks you've made a typo in a variable name, it would be very difficult to track down a typo in a hash key.

      Any other thoughts?

      thanks
      MFN

        How many functions are there return hashrefs? Is it a great big deal to tie the hashes before filling and returning them?


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon