File Coverage

blib/lib/Text/Perfide/BookPairs.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Text::Perfide::BookPairs;
2              
3 1     1   22955 use 5.006;
  1         4  
  1         38  
4 1     1   5 use strict;
  1         2  
  1         34  
5 1     1   6 use warnings;
  1         7  
  1         29  
6 1     1   1158 use Data::Dumper;
  1         16736  
  1         83  
7 1     1   547 use Text::Perfide::WordBags;
  0            
  0            
8             use File::Path;
9             use File::Basename;
10             use utf8::all;
11              
12             =head1 NAME
13              
14             Text::Perfide::BookPairs - Find different-language pairs of books in a collection.
15              
16             =head1 VERSION
17              
18             Version 0.01_03
19              
20             =cut
21              
22             our $VERSION = '0.01_03';
23              
24             use base 'Exporter';
25             our @EXPORT = (qw/ calc_dupvers
26             calc_bpairs
27             calc_default
28             calcpair haspn
29             txt2bag2 rmbagfiles
30             calcbagfiles
31             bagfile
32             debug_pairs
33             print_dupvers
34             print_default
35             print_bpairs
36             /);
37              
38              
39             =head1 SYNOPSIS
40              
41             Quick summary of what the module does.
42              
43             Perhaps a little code snippet.
44              
45             use Text::Perfide::BookPairs;
46              
47             my $foo = Text::Perfide::BookPairs->new();
48             ...
49              
50             =head1 EXPORT
51              
52             A list of functions that can be exported. You can delete this section
53             if you don't export anything, such as for a purely object-oriented module.
54              
55             =head1 SUBROUTINES/METHODS
56             =cut
57              
58             # our($bpairs,$rv,$av,$warn,$debug,$v,$nr,$same,$dv,$recalc,$normbf);
59             # $nr //= 3;
60             # $rv //= 0.2;
61             # $av //= 0.4;
62             # $dv //= 0.9;
63              
64             =head2 calc_dupvers
65              
66             Tries to find repeated versions in all the files passed as argument.
67             =cut
68              
69             sub calc_dupvers {
70             my ($files,$options) = @_;
71             foreach my $file1 (@$files){
72             my $bag1 = bagfile($file1,\&txt2bag2);
73             my $list = {};
74             foreach my $file2 (@$files){
75             next if $file1 eq $file2;
76             $list->{$file2} = calcpair($file1,$bag1,$file2);
77             }
78             print_dupvers($file1,$list,$options);
79             }
80             }
81              
82             =head2 print_dupvers
83             =cut
84              
85             sub print_dupvers {
86             my ($file1,$list,$options) = @_;
87             my @cenas = (grep {$list->{$_}{value} >= $options->{dv}} keys %$list);
88             my @tmp = sort {$list->{$b}{value} cmp $list->{$a}{value}} @cenas;
89             if (@tmp){
90             print "$file1\n";
91             my $nr = $options->{nr};
92             $nr = $#tmp if $nr > $#tmp;
93             foreach(@tmp[0..$nr]){
94             print $list->{$_}{stats} if defined($options->{v});
95             print "\t$_\n";
96             }
97             print "\n";
98             }
99             }
100              
101             =head2 calc_bpairs
102              
103             Pairs the first argument with the following arguments, and prints output compatible with Text::Perfide::BookSync
104              
105             =cut
106              
107             sub calc_bpairs {
108             my ($files,$options) = @_;
109             my $file1 = shift @$files;
110             my $bag1 = bagfile($file1,\&txt2bag2);
111             my $list = {};
112             foreach my $file2 (@$files){
113             next if $file1 eq $file2;
114             $list->{$file2} = calcpair($file1,$bag1,$file2);
115             }
116             print_bpairs($file1,$list,$options);
117             }
118              
119             =head2 print_bpairs
120             =cut
121              
122             sub print_bpairs {
123             my ($file1,$list,$options) = @_;
124             my $f2 = (sort {$list->{$b}{value} cmp $list->{$a}{value}} keys %$list)[0];
125             if($options->{warn}){
126             if(defined($options->{v}) and ($list->{$f2}{value} <= $options->{av})){ print "# ",$list->{$f2}{stats},"\t"; }
127             else{
128             if ($list->{$f2}{value} <= $options->{rv}) { print "# X\t"; }
129             elsif ($list->{$f2}{value} < $options->{av}) { print "# ?\t"; }
130             }
131             print "$file1\t$f2\n";
132             }
133             else { print "$file1\t$f2\n" if $list->{$f2}{value} >= $options->{av}; }
134             }
135              
136             =head2 calc_default
137              
138             Tries to pair the first argument with all the remaining arguments.
139              
140             =cut
141              
142             sub calc_default {
143             my ($files,$options) = @_;
144             my $file1 = shift @$files;
145             my $bag1 = bagfile($file1,\&txt2bag2);
146             my $list = {};
147             foreach my $file2 (@$files){
148             next if $file1 eq $file2;
149             $list->{$file2} = calcpair($file1,$bag1,$file2);
150             }
151             print_default($file1,$list,$options);
152             }
153              
154             =head2 print_default
155             =cut
156              
157             sub print_default {
158             my ($file1,$list,$options) = @_;
159             my $nr = $options->{nr};
160             $nr = int(keys %$list) if $nr > keys %$list;
161             print "$file1\n";
162             foreach((sort {$list->{$b}{value} cmp $list->{$a}{value}} keys %$list)[0..$nr-1]){
163             print $list->{$_}{stats},"\t";
164             print "$_\n";
165             }
166             print "\n";
167             }
168              
169             =head2 calcpair
170             =cut
171              
172             sub calcpair {
173             my ($file1,$bag1,$file2,$options) = @_;
174             return undef if $file1 eq $file2;
175              
176             my $bag2 = bagfile($file2,\&txt2bag2);
177             my $value = pairability($bag1,$bag2);
178             my $stats = sprintf "(%0.3f) [%d,%d]",$value,bagcard($bag1),bagcard($bag2);
179             debug_pairs($file1,$file2,$bag1,$bag2) if defined($options->{debug});
180             return {value => $value,
181             stats => $stats,};
182             }
183              
184             =head2 haspn
185             =cut
186              
187             sub haspn {
188             my $bag = shift;
189             my $have = 0;
190             foreach(32..52){
191             $have++ if defined($bag->{$_} and $bag->{$_}==1);
192             }
193             return 1 if $have > 10;
194             return 0;
195             }
196              
197              
198             =head2 txt2bag2
199              
200             Given a text, creates a bag of words containing all the words starting with caps and which do not appear also starting with small caps.
201              
202             =cut
203              
204             sub txt2bag2{
205             my $text = shift;
206             my $uru = qr{[\x{0410}-\x{042F}]};
207             #my $uru = qr{[АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ]};
208             my $lru = qr{[\x{0430}-\x{044F}]};
209             #my $lru = qr{[абвгдеёжзийклмнопрстуфхцчшщъыьэюя]};
210             #my $ul = qr{[A-Z]|$uru};
211             #my $ll = qr{[a-z]|$lru};
212             my $w = qr{\w|$uru|$lru};
213              
214             my $upper = {};
215             my $uppat = qr{\b[A-Z]\w{3,}(?:['-]\w+)*\b};
216             #my $uppat = qr{\b$ul$w{3,}(?:['-]$w+)*\b};
217             $upper->{$1}++ while($text =~ /($uppat)/g);
218              
219             my $lower = {};
220             my $lwpat = qr{\b[a-z]+(?:['-][a-z]+)*\b};
221             #my $lwpat = qr{\b$ll+(?:['-]$ll+)*\b};
222             $lower->{$1}++ while($text =~ /($lwpat)/g);
223              
224             my $ruppat = qr/$uru$lru+/;
225             #my $ruppat = qr/(?:^|\s)$uru$w{3,}(?:['-]$w+)*(?:\s|,|\.)/;
226             $upper->{$1}++ while($text =~ /($ruppat)/g);
227            
228             my $rlwpat = qr/$lru+/;
229             #my $rlwpat = qr{(?:^|\s)$lru+(?:['-]$lru+)*(?:\s|,|\.)};
230             $lower->{$1}++ while($text =~ /($rlwpat)/g);
231            
232             foreach my $k (keys %$upper){
233             if($lower->{lc $k}){
234             my $ratio = $upper->{$k}/$lower->{lc $k};
235             delete $upper->{$k} if $ratio < 10;
236             }
237             }
238             return $upper;
239             }
240              
241             # sub txt2bag{
242             # my $text = shift;
243             # my $bag = {};
244             # my $pecul = qr{\d+};
245             # $bag->{$1}++ while($text =~ /($pecul)/g);
246             # if(haspn($bag)){
247             # foreach(1..300){
248             # $bag->{$_}-- if $bag->{$_};
249             # delete $bag->{$_} unless $bag->{$_};
250             # }
251             # }
252             # return $bag;
253             # }
254              
255             =head2 rmbagfiles
256             =cut
257              
258             sub rmbagfiles {
259             my $list = shift;
260             #print STDERR "Removing '__bags' directories:\n";
261             foreach my $path (@$list){
262             $path = dirname($path) unless -d $path;
263             $path.='/__bags' unless $path =~ /__bags$/;
264             if ($path =~ m{__bags/?$}){
265             #print STDERR "\t'$path'\n";
266             rmtree($path);
267             }
268             else {
269             print STDERR "Directory '$path' does not end with'__bags'. Won't remove.\n";
270             }
271             }
272             print STDERR "\n";
273             }
274              
275             =head2 calcbagfiles
276            
277             Given a list of files, calculates the bag files unless they already exist.
278              
279             =cut
280              
281             sub calcbagfiles {
282             my ($list,$options) = @_;
283             map { bagfile($_,\&txt2bag2,$options) } @$list;
284             }
285              
286             =head2 bagfile
287              
288             Uses a given function to calculate the wordbag of a given file. Dumps the results to a folder '__bags' in the same folder where the file is located.
289              
290             =cut
291              
292             sub bagfile {
293             my ($txtfile,$func,$options) = @_;
294             my $dir = dirname($txtfile);
295             my $base = basename($txtfile);
296             mkdir "$dir/__bags" unless -e "$dir/__bags";
297             return do "$dir/__bags/$base.bag" if (-e "$dir/__bags/$base.bag" and !defined($options->{recalc}));
298              
299             my $bag = file2bag($func,$txtfile);
300             open my $bagfile,'>',"$dir/__bags/$base.bag";
301             print $bagfile Dumper($bag);
302             close $bagfile;
303             return $bag;
304             }
305              
306             =head2 debug_pairs
307             =cut
308              
309             sub debug_pairs{
310             my ($f1,$f2,$bag1,$bag2) = @_;
311             $f1 =~ s{^.*/}{};
312             $f2 =~ s{^.*/}{};
313             open DEBUG,'>',"$f1"."_$f2.debug_pair";
314             print DEBUG Dumper(bagint($bag1,$bag2));
315             close DEBUG;
316             open DEBUG,'>',"$f1.debug";
317             print DEBUG Dumper($bag1);
318             close DEBUG;
319             open DEBUG,'>',"$f2.debug";
320             print DEBUG Dumper($bag2);
321             }
322              
323              
324             =head1 AUTHOR
325              
326             Andre Santos, C<< >>
327              
328             =head1 BUGS
329              
330             Please report any bugs or feature requests to C, or through
331             the web interface at L. I will be notified, and then you'll
332             automatically be notified of progress on your bug as I make changes.
333              
334             =head1 ACKNOWLEDGEMENTS
335              
336              
337             =head1 LICENSE AND COPYRIGHT
338              
339             Copyright 2011 Project Natura.
340              
341             This program is free software; you can redistribute it and/or modify it
342             under the terms of either: the GNU General Public License as published
343             by the Free Software Foundation; or the Artistic License.
344              
345             See http://dev.perl.org/licenses/ for more information.
346              
347              
348             =cut
349              
350             1; # End of Text::Perfide::BookPairs