How can I change the case of a hash key?

I am writing a script which is likely to be modified by users. Currently I am storing the configuration settings inside the script. It exists in the form of a hash-of-hashes.

I would like to guard against people accidentally using lowercase characters in the hash keys, because that will break my script.

It would be simple to inspect the hash keys and merely issue warnings for any keys with lowercase characters, but I would rather fix the case sensitivity automatically.

In other words, I want to convert all the hash keys in the top-level hash to uppercase.

Answers


Andy's answer is a good answer, except he ucs every key, and then ucs it again if it doesn't match.

This ucs it once:

%hash = map { uc $_ => $hash{$_} } keys %hash;

But since you spoke of users storing keys, a tie is a much more sure way, even if slower.

package UCaseHash;
require Tie::Hash;

our @ISA = qw<Tie::StdHash>;

sub FETCH { 
    my ( $self, $key ) = @_;
    return $self->{ uc $key };
}

sub STORE { 
    my ( $self, $key, $value ) = @_;
    $self->{ uc $key } = $value;
}

1;

And then in main:

tie my %hash, 'UCaseHash'; 

That's a show. The tie "magic" encapsulates it, so the users can't unknowingly mess with it.

Of course, as long as you're using a "class", you can pass in the config file name and initialize it from there:

package UCaseHash;
use Tie::Hash;
use Carp qw<croak>;

...

sub TIEHASH { 
    my ( $class_name, $config_file_path ) = @_;
    my $self = $class_name->SUPER::TIEHASH;
    open my $fh, '<', $config_file_path 
        or croak "Could not open config file $config_file_path!"
        ;
    my %phash = _process_config_lines( <$fh> );
    close $fh;
    $self->STORE( $_, $phash{$_} ) foreach keys %phash;
    return $self;
}

Where you would have to call it like:

tie my %hash, 'UCaseHash', CONFIG_FILE_PATH;

...assuming some constant CONFIG_FILE_PATH.


Walk through the hash and replace any lowercase keys with their uppercase equivalents, and delete the old ones. Roughly:

for my $key ( grep { uc($_) ne $_ } keys %hash ) {
    my $newkey = uc $key;
    $hash{$newkey} = delete $hash{$key};
}

This will convert multi level hash to lowercase

my $lowercaseghash = convertmaptolowercase(\%hash);

sub convertmaptolowercase(){
    my $output=$_[0];
    while(my($key,$value) = each(%$output)){
        my $ref;
        if(ref($value) eq "HASH"){
            $ref=convertmaptolowercase($value);
        } else {
           $ref=$value;
        }
        delete $output->{$key}; #Removing the existing key
        $key = lc $key;
        $output->{$key}=$ref; #Adding new key
    }
    return $output;
}

Need Your Help

SMS notification when selected friends are online

facebook sms

I have an idea to develop a Facebook app which notifies the user through SMS when his/her friends come online. The user can pre-select the friends he/she wanted to get SMS notifications of.