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

Hello informed people...

So, I have a very gooky specification, a program takes in text from the command line; like "Hello, how are you", then saves aforesaid text character by character as a folder.

So H gets turned into '01234.H.something' and , into '01234.Comma.something'.

Another program then scans the folder and reads the folder names with a certain prefix and concatonates everything back together before sending it off to get processed and returning a string of its own to be saved as folder names. (I know, very wierd protocol, not my fault ><).

Problem is:
The data comes out of STDIN fine, or out of the response, and is saved fine into the folder names according to a hash table that maps up all the values. BUT during the read process it gets mangled into something like this:

Hello My Name is Chris: 0ell0 0y0name0i0C0ris

There doesnt appear to be any logic to the mangling, and i'm at a loss as to what is causing it; although it seems to be linked to my hashtable which is being searched like this:

sub findCharacterAsKey { my $loebnerLetter = shift; while (($key, $value) = each %$keymap) { if($loebnerLetter eq $value) { printf("$loebnerLetter maps to $value so returning $key\n"); + return $key; } } }

Any help would be appreciated, thanks.

Replies are listed 'Best First'.
Re: File Reading and Hash Accessing that isn't doing what you'd expect.
by moritz (Cardinal) on Jun 01, 2010 at 14:09 UTC
    It seems to be related to the hash table, yet you don't show us the table.

    Anyway, one problem with your code is that you iterate over a hash, abort in the middle and don't reset the iterator.

    Iterating over a hash is a bad idea anyway - just store it the other way round (ie turn the values into keys and the other way round), and do a lookup:

    # assuming you have no duplicate values: my %mapkey = reverse %keymap; sub findCharacterAsKey { my $loebnerLetter = shift; if (exists $mapkey{$lobnerLetter}) { return $mapkey{$lobnerLetter}; } else { warn "Could not resolve '$loebnerLetter'"; } }

    Since you have to do the inversion of the hash only once, it'll be much faster and correct this way.

    Perl 6 - links to (nearly) everything that is Perl 6.

      Many thanks to everyone here!

      I didn't realise reversing a hashtable was simply a matter of using reverse, that will hopefully solve all my problems. Additionally I didn't know that iterators needed to be reset (oops).

      I know I was using it incorrectly (goes to show that trying to hack your way around causes unforeseen problems), just didnt know how to turn the hash around without having to re-edit it again since its a hard-coded map.

      Thanks a lot guys, will see if this helps.

        perlfaq4 might also be relevant for you. The start "just" talks about numbers, but later on section on hashes might really help you.
Re: File Reading and Hash Accessing that isn't doing what you'd expect.
by kennethk (Abbot) on Jun 01, 2010 at 14:25 UTC
    Following on moritz's comment, I'll point out what is likely happening. Since your iterator is never reset and you are looping over a hash, every few times your call your subroutine (actual frequency depends on what letters you pass it), you have exhausted the iterator on your hash. Since your return statement only gets executed with a successful match, you exit your subroutine without explicitly specifying a value. Perl therefore returns the result of the last evaluation, which I think is the logical state of the each statement - that is why you get zeros.

    I'd also point out that $key and $value are not localized to the loop (probably ought to read my ($key, $value)). Assuming you are using and passing strict, this means you have actually created a closure and are possibly clobbering similarly named variables elsewhere in the code.

Re: File Reading and Hash Accessing that isn't doing what you'd expect.
by toolic (Bishop) on Jun 01, 2010 at 14:11 UTC
    This is probably unrelated to your problem, but you should use print instead of printf, since you are not specifying a FORMAT.

    We could help you better if you showed us how you call your function and what your variables contain. Sprinkle more prints in your code to help yourself debug.

Re: File Reading and Hash Accessing that isn't doing what you'd expect.
by JavaFan (Canon) on Jun 01, 2010 at 14:21 UTC
    Ah, the pitfalls of each - leaving the hash in a certain state when aborted halfway. The simplest fix would be to call keys (in void context) on the hash before looping over them. Better would be to use a hash indexed on the values - then you can do a simple lookup instead of a iterating.