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

I'm working on an IRC server written in Perl (not for any serious use, but just as a pet project of mine) and I'm running into a little trouble.

I store nicknames as keys in a hash named %fhs. The value of each of those entries is the filehandle for the nickname in question, so when I need to send Bob89 data, I can just grab his filehandle from $fhs{Bob89}. The problem is, if a user wants to send information to Bob89, but sends it to bOb89, $fhs{bOb89} is checked for the filehandle and returns nothing. In order to get around this, I've had to do a case insensitive search and traverse the entire hash until I get a match with this code:
sub nick_ison { my ($nick) = @_; foreach my $nick_check (keys %fhs) { print "NICK: $nick\n"; print "NICK CHECK: $nick_check\n"; if ($nick =~ /^($nick_check)$/i) { return $nick_check } } return; }
That way I can use the returned nickname in the correct case and everything works just fine. The problem is, this doesn't seem very efficient and I was wondering if there was a quicker way to do it.

Also, with this code, I run into problems with nicknames that contain characters used as regex metacharacters and quantifiers.

For example, when Bob89^ is an online nick, nick_ison('Bob89^') prints Bob89^ as both the value of $nick and $nick_check, but the regex doesn't match it and I haven't been able to figure out a way to escape all the characters and have it still work. I tried escaping all the characters by just taking them and putting \ in front of them, but it started getting complicated when someone changed their nick to Bob89\^ and it erroneously matched Bob89^.

So basically, is there a quicker way to do this and if not, what would be the best way of taking the nickname and escaping all the regex characters before using it to check for the filehandle?

I'm really looking for a quicker way to write this subroutine, but if you have a way to improve the code I have, it'd be much appreciated.

Replies are listed 'Best First'.
Re: Problem With Perl IRC Server
by Juerd (Abbot) on Jan 26, 2002 at 21:43 UTC
    For a case insensitive hash, you could use a tied hash, but it's a lot easier to just always lowercase the keys. $hash{ lc $key }

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

      Ah, that works perfectly! Thank you very much.
Re: Problem With Perl IRC Server
by Aristotle (Chancellor) on Jan 26, 2002 at 23:46 UTC

    Go with lc.

    If this hash only holds filehandles and the rest of the user info is stored elsewhere then just store lowercased nicks and look up lowercased nicks, like Juerd++ suggested.

    If you really have reason not to do that, then you should use an array (or a pair of arrays) since that's more efficient to step through than a hash. However, remember that avoiding the expensive stepping through arrays to find a single value is what hashes were made for. Anyway, if you stick with that approach, do my $nick = lc shift; first so you don't need to repeatedly lowercase the nick within the loop, then use return $nick_check if $nick eq lc $nick_check; rather than a regex.

    Makeshifts last the longest.

Re: Problem With Perl IRC Server
by talexb (Chancellor) on Jan 26, 2002 at 21:51 UTC
    The one-liner
    perl -e "$a='Rob89$';print$a.':';$a=~s/(\W)/\\$1/g;print$a;"
    produces a string where everything that might be magical is escaped. Would that work?

    --t. alex

    "Of course, you realize that this means war." -- Bugs Bunny.

      Perl has that built-in, and it's called quotemeta.

      2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

Re: Problem With Perl IRC Server
by strat (Canon) on Jan 28, 2002 at 20:29 UTC
    With a tied hash, you can use hashkeys in a case independend way. But this way takes some more ressources than just an ordinary lc-Compare, so I think it might not be the best idea using it with a server...

    Best regards,
    perl -e "$_=*F=>y~\*martinF~stronat~=>s~[^\w]~~g=>chop,print"

Re: Problem With Perl IRC Server
by beebware (Pilgrim) on Jan 27, 2002 at 01:44 UTC
    Go for $nick_check=$fhs(lc ($nick));.