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

I have a hash that has key/value pairs of entities that need to be replaced, thus:
%iso8859 = ( "\xA0" => ' ', "\xA1" => '¡', "\xA2" => '¢', "\xA3" => '£', "\xA4" => '¤', "\xA5" => '¥', "\xA6" => '¦', ...
So how do I take a string and substitute characters from the key to the value? I want to do something like: s/keys(%iso8859)/values(%iso8859)/g; But, of course, that doesn't work. How can I do this?

Replies are listed 'Best First'.
Re: substitute using a hash
by broquaint (Abbot) on May 07, 2002 at 17:31 UTC
    Although there's undoubtedly a perl module out there doing what you want to do from the looks of it (and it's likely to be HTML::Entities), here's some code to help you on your way
    my %iso8859 = ( "\xA0" => ' ', "\xA1" => '¡', "\xA2" => '¢', "\xA3" => '£', "\xA4" => '¤', "\xA5" => '¥', "\xA6" => '¦', ); my $string = "a £ a penny"; my $regex = join '|', map quotemeta, keys %iso8859; $string =~ s/($regex)/$iso8859{$1}/g; print $string; __output__ a £ a penny
    You may not need the quotemeta() in the map() but I've just added it 'just in case'.
    HTH

    _________
    broquaint

      Yup. That did the trick. Very cool. I'll also look at HTML::Entities. If it doesn't have this in there, I'll be sure to contribute this snippet. Thanks!
Re: substitute using a hash
by VSarkiss (Monsignor) on May 07, 2002 at 17:34 UTC

    I'm a little afraid about where you're going to use this, but.... ;-)

    The key is to substitute each one at a time, like this:

    while (my ($left, $right) = each %iso8859) { $str =~ s/$left/$right/g; }
    HTH

Re: substitute using a hash
by RMGir (Prior) on May 07, 2002 at 17:44 UTC
    I think building up a subref by evaluating constructed code is likely the best option.

    my $subCode = "sub {"; $subCode.=(join "\n", map {'$_[0]=~s/'.$_.'/'.$iso8859{$_}.'/g;'} keys %iso8859); $subCode.="}"; print "$subStr\n"; my $sub=eval $subStr; $sub->($string);

    You want to make sure that none of the keys appear in any of the substitution values, of course, or this gets more complicated...
    --
    Mike

    Edit: D'oh, took too long writing my response, my first 2 alternatives had already been posted once I hit submit, so edited them out...

Re: substitute using a hash
by emilford (Friar) on May 07, 2002 at 17:30 UTC
    I'm not sure what you want to do exactly, but if you want to just substitute the hash key into the corresponding hash value, this will work.
    # here's the hash %s = ( "substring1" => 'string1', "substring2" => 'string2', "substring3" => 'string3' ); # get the current keys @keys = keys(%s); # go through each key and sway the key/value foreach $key (@keys) { $s{$key} = $key; # print out the swapped hash value print "$s{$key}\n"; } Output ---------------------------------- substring1 substring2 substring3
    Not sure if this was what you were looking for or if there is a better way to do it with regexps, but maybe this will help a little. -Eric
      Oooops, I had a feeling that wasn't what you were looking for. At least the other monks answered your question correctly. :P
Re: substitute using a hash
by hopes (Friar) on May 07, 2002 at 18:42 UTC
    How about the traditional way?
    for (keys %iso8859){ $string=~s/$_/$iso8859{$_}/gi; } print $string;


    Hopes
    $_=$,=q,\,@4O,,s,^$,$\,,s,s,^,b9,s, $_^=q,$\^-]!,,print
Re: substitute using a hash
by mephit (Scribe) on May 07, 2002 at 21:03 UTC
    foreach (keys %iso8859) { $str =~ s/$_/$iso8859{$_}/g; }
    or...
    $str =~ s/([\xA0-\xFF])/{$iso8859{$1} ? $iso8859{$1} : $1 }/ge;
    This one would be useful if you only have iso8859 values for *some* hex characters. You can do without that block on the right side (and the trailing /e as well) if you make sure that every value in the range given on the left side is defined in the hash and has a value. For example:
    $str =~ s/([\xA0-\xA6])/$iso8859{$1}/g;
    HTH,

    Mephit (who's learning things as of late by offering replies)

Re: substitute using a hash
by indapa (Monk) on May 07, 2002 at 17:35 UTC
    Are you trying invert the hash? From the Cookbook 5.8:
    %reverse = reverse %iso8859;
    %reverse then has values whose keys are of the original hash and vice versa.