File Coverage

blib/lib/Text/Levenshtein/Damerau/PP.pm
Criterion Covered Total %
statement 37 42 88.1
branch 10 10 100.0
condition 11 12 91.6
subroutine 4 4 100.0
pod 1 1 100.0
total 63 69 91.3


line stmt bran cond sub pod time code
1             package Text::Levenshtein::Damerau::PP;
2 6     6   24995 use 5.008_008; # for utf8, sorry legacy Perls
  6         57  
  6         405  
3 6     6   35 use strict;
  6         10  
  6         227  
4 6     6   30 use List::Util qw/min/;
  6         10  
  6         3425  
5             require Exporter;
6            
7             our @ISA = qw(Exporter);
8             our @EXPORT_OK = qw/pp_edistance/;
9             our $VERSION = '0.25';
10              
11             sub pp_edistance {
12             # Does the actual calculation on a pair of strings
13 63     63 1 142 my ( $source, $target, $max_distance ) = @_;
14 63   100     235 $max_distance = int($max_distance || 0);
15              
16 63   100     181 my $source_length = length($source) || 0;
17 63   100     148 my $target_length = length($target) || 0;
18 63 100 66     2713 return ($source_length?$source_length:$target_length) if(!$target_length || !$source_length);
    100          
19              
20 53         71 my $lengths_max = $source_length + $target_length;
21 53         56 my $dictionary_count; #create dictionary to keep character count
22             my $swap_count;
23 0         0 my $swap_score;
24 0         0 my $target_char_count;
25 0         0 my $source_index;
26 0         0 my $target_index;
27 0         0 my @scores;
28              
29             # init values outside of work loops
30 53         827 $scores[0][0] = $scores[1][0] = $scores[0][1] = $lengths_max;
31 53         72 $scores[1][1] = 0;
32              
33             # Work Loops
34 53         278 foreach $source_index ( 1 .. $source_length ) {
35 205         215 $swap_count = 0;
36 205         386 $dictionary_count->{ substr( $source, $source_index - 1, 1 ) } = 0;
37 205         367 $scores[ $source_index + 1 ][1] = $source_index;
38 205         266 $scores[ $source_index + 1 ][0] = $lengths_max;
39              
40 205         296 foreach $target_index ( 1 .. $target_length ) {
41 903 100       2281 if ( $source_index == 1 ) {
42 230         818 $dictionary_count->{ substr( $target, $target_index - 1, 1 ) } = 0;
43 230         2076 $scores[1][ $target_index + 1 ] = $target_index;
44 230         383 $scores[0][ $target_index + 1 ] = $lengths_max;
45             }
46              
47             $target_char_count =
48 903         1889 $dictionary_count->{ substr( $target, $target_index - 1, 1 ) };
49 903         1408 $swap_score = $scores[$target_char_count][$swap_count] +
50             ( $source_index - $target_char_count - 1 ) + 1 +
51             ( $target_index - $swap_count - 1 );
52              
53 903 100       2399 if (
54             substr( $source, $source_index - 1, 1 ) ne
55             substr( $target, $target_index - 1, 1 ) )
56             {
57 667         2885 $scores[ $source_index + 1 ][ $target_index + 1 ] = min(
58             $scores[$source_index][$target_index]+1,
59             $scores[ $source_index + 1 ][$target_index]+1,
60             $scores[$source_index][ $target_index + 1 ]+1,
61             $swap_score
62             );
63             }
64             else {
65 236         1090 $swap_count = $target_index;
66              
67 236         741 $scores[ $source_index + 1 ][ $target_index + 1 ] = min(
68             $scores[$source_index][$target_index], $swap_score
69             );
70             }
71             }
72              
73             #unless ( $max_distance == 0 || $max_distance >= $scores[ $source_index + 1 ][ $target_length + 1 ] )
74             #{
75             # return -1;
76             #}
77              
78 205         562 $dictionary_count->{ substr( $source, $source_index - 1, 1 ) } =
79             $source_index;
80             }
81            
82 53         95 my $score = $scores[$source_length+1][$target_length+1];
83 53 100 100     514 return ($max_distance != 0 && $max_distance < $score)?(-1):$score;
84             }
85            
86             1;
87              
88             __END__