[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Dict.pm for 0.49



I think I out did myself (a.k.a. "Vacation time is a good thing")

Now you can specify what dictionary to use (or defaults to wordnet), and
it does a "Levensetein distance one matching strategy" to try and find a
similar word.  It does require the Net::Dict module (tests for it), and it
can get really, really wordy, which is the concern about the message
length.

Lemme know if you find anything goofy, or just plain broken, some words
may break it, but I haven't found any and I'm running out of words to try.

Here are some examples taken from 0.49_2:

> define insult
insult n 1: a rude expression intended to offend or hurt; (blah blah)

> define inslut
inslut: No Match. Perhaps you mean: insult

> define lifen
lifen: No Match. Perhaps you mean:  lien, life, liken, limen, linen, liven
or lifer; or try using: web1913

> define lifen using web1913
Lifen \Lif"en\ (l[imac]f"'n), v. t. To enliven. [Obs.] --Marston. 

> define nslookup
nslookup: No match, try using foldoc.

> define nslookup using foldoc
nslookup  A {Unix} utility by Andrew Cherenson for querying {Internet}
{domain name server}s. .... (blah blah)


cool beans,
Jay
(teckle)
# 
#  Dict -- infobot module for Dictionary lookups.
# 	   requires the Net::Dict module.
#  By Jay Jacobs (teckle)
#

package Infobot::Module::Dict;


use strict;
use Infobot::Module;

$Infobot::Module::Dict::VERSION = "0.01_00";
$Infobot::Module{"Dict"} = $Infobot::Module::Dict::VERSION;
@Infobot::Module::Dict::ISA = qw(Infobot::Module);

my $anybad;

BEGIN {
    $anybad = '';
    eval { require Net::Dict};
    if ($@) {
      $anybad = "Net::Dict"; 
      warn "Infobot::Module::Dict requires $anybad to work"
          . "You can get it from htt://www.perl.com/CPAN/ or use "
          . "the CPAN installer:  "
          . "perl -MCPAN -e 'install $anybad'";
    }
}

sub new {
  return undef if $anybad;
  my $class = shift ;
  my $self  = $class->SUPER::new(@_);

  $self->weight(1); 

  $self->name('Dict');
  $self->regex(qr/^define (\S+)(\s+using\s+)?(\S+)?/i);
  $self->usage("define <word> [using DICT], where DICT is an accepted dictionary defaults to wordnet 'wn'");
  $self->descrip("Lookups up a word (or a close match) using the default 'wordnet' dictionary, or one specified");
  ($anybad)?$self->enabled(1):$self->enabled(0);

  bless $self, $class;
}

sub action {
  my $self = shift ;
  return undef unless defined $self and $self->enabled;

  my $message = shift; 
  return undef unless $message;
  my ($word, undef, $dict) = @{$message->get('args')};
  $dict = "wn" if (! defined $dict);
  $self->status(3, "looking up \"$word\" in dictionary: \"$dict\"");
  # my $Ret = "Looking up the word: \"$word\"";
  # $Ret.=", in the dictionary \"$dict\"";
  # $Ret.=".";
  # return($Ret);
  my $server = Net::Dict->new("dict.org");
  my $h = $server->define($word);
  my ($i, $Ret, $dct, $def);
  my $found = 0;
  my @other_matches;
  if (! defined @{$h}) {
    $self->status(3, "No match Found at all, looking up alternatives");
    $Ret = findmatch($server, $dict, $word);
  } else {
    foreach $i (@{$h}) {
      ($dct, $def) = @{$i};
      if ($dct eq $dict) {
        foreach (split(/\n/, $def)) {
	  $_=~s/\s{3,}//g;
	  # $_=~s/\s+$//g;
	  $Ret.=$_." ";
        }
      } else {
        push(@other_matches, $dct);
      }
    }
    if (! $Ret) {
      $self->status(3, "match found in other dict, looking up alternatives");
      $Ret = findmatch($server, $dict, $word, @other_matches);
    }
  }
  return($Ret);
}

sub findmatch {
  my $server = shift;
  my $dict = shift;
  my $word = shift;
  my @other_matches = @_;
  my @others;
  my ($h, $i, $dct, $def);
  $h = $server->match($word, "lev");
  foreach $i (@{$h}) {
    ($dct, $def) = @{$i};
    push (@others, $def) if ($dct eq $dict);
  }
  if (@others) {
    my $str = gimmePretty(@others);
    if (@other_matches) {
      $str.="; or try using: ".(gimmePretty(@other_matches));
    }
    return("$word: No Match. Perhaps you mean: $str");
  } elsif (@other_matches) {
    return("$word: No match, try using ".(gimmePretty(@other_matches)).".");
  } else {
    return "$word: No matches found";
  }
}

sub gimmePretty {
  my @words = @_;
  my $str = "";
  if ($#words>=1) {
    for (0..($#words-1)) {
      $words[$_]=~s/"//g;
      $str .= " $words[$_],";
    }
    chop($str);
    $str .= " or ";
  }
  $words[$#words]=~s/"//g;
  $str .= $words[$#words];
  return($str);
}
1;

=pod

=head1 NAME

Infobot::Module::Dict - Word definition module for infobot

=head1 SYNOPSIS

define <word> [using <dictionary>]

=head1 DESCRIPTION

Uses the Net::Dict module to lookup a word for a specific 
dictionary.  If the dictionary isn't specified, it will 
default to use the "wordnet" (wn) dictionary.  It will try
to return a definition from the dictionary, if it doesn't
find one, it will try to find close matches using the 
Levensetein distance one matching strategy.  If it found
the word in other dictionaries, it will also mention those
as a possible place to look.

=head1 AUTHORS

Jay Jacobs (teckle)
jjacobs@securetty.org