|
Задача, сделать поисковик чтобы оценивал похожесть, степень одинаковости
предложений и текста.
#!/usr/bin/perl -w use locale; %oo=("будет"=>1, "африка"=>1, "завтра"=>1); $b="африка африка будет завтра африка"; $o="африка будет урааа зачем африка"; $tw="африка небудет вчера будет завтра"; $tb="аляска аляска будет будет будет сегодня"; @m=($b, $o, $tb, $tw); rrand(\@m); print join "\n", @m,"\n"; for $i(0 .. $#m){ $h{$i}{$1}++ while $m[$i]=~m!((\w[\w-]*){4,30})!g; $vr{$i}=$m[$i]; } for $r(keys %h){print "\n"; my (@ee, $u, $trr); for $n(keys %{$h{$r}}){ do{ $t = join " " => $vr{$r}; $u+=1; push @ee => $h{$r}{$n}; } if exists $oo{$n}; } print "$t ",$u + $ee[0]-1,"\n"; } sub rrand{ my $m = shift; my $i; for($i=@$m; --$i;){ my $j = int rand($i+1); next if $i==$j; @$m[$i,$j] = @$m[$j,$i] } }
есть какой-то текст в переменнах $b,$o,$tw,$tb, загоняется все в массив. Для отладки пишется подпрограмма rrand(), которая переставляет случаным образом элементы массива. Далее идет цикл, подсчитывающий частоты одинаковых слов в переменных и заносящий эти частоты в хеш хешей. Регулярное выражение while $m[$i]=~m!((\w[\w-]*){4,30})!g; вырезает по одному слову через пробел, причем ширина слова не менее 4 букв и не более 30. В силу действия модификатора g работает цикл, заполняющий хэш хешей. В хеше хешей 1(т.к. нуумерация элементов массива была случаный образом изменена, то удобно обращаться через номер массива) содержатся предположим для переменной $b такие данные:
$b = "африка африка будет завтра африка"; $h{1}=( "африка" => 3, "будет" => 1, "завтра" => 1 );
т.е. слово африка по частоте употребления в три раза больше в файле, что дает ему большие шансы вылезти в список перых результатов. Далее следуют слова будет и завтра, которые так-же играют немаловажную роль в поднятии ссылки наверх из результатов поискового запроса. Далее в цикле объявляется хеш(задача была сделать, а не память сэкономить), который будет выводить результаты запроса.
Далее идет цикл:
for $r(keys %h){print "\n"; my (@ee, $u, $trr); for $n(keys %{$h{$r}}){ do{ $t = join " " => $vr{$r}; $u++; push @ee => $h{$r}{$n}; } if exists $oo{$n}; } print "$t ",$u + $ee[0]-1,"\n"; }
запрашиваем численное название хеша в переменную $r, считываем с её помощью хеши хешей. Здесь функцией exists реализован поиск общих ключей в двух хешах: в хеше, поступающем на ввод, и текущем по шагу цикла хеше хешей. Если информация содержится в начальном втором хеше %vr, то запрашиваем её $vr{$r}. Строчка $u++ отвечает за количество вхождений всех слов, заданных в запросе, в искомую строку(файл). Допустим на входе фраза "будет африка завтра", если хотя бы одно слово из этой фразы совпало со словом в очередной строке(ведь изначально строка была побита на частотный хеш) то локальная переменная $u увеличит свое значение на единичку. Если два слова в строке и в запросе одинаковы, то $u=2, если три - $u=3 и так далее, слов в запросе может быть любое количество. Далее идет строчка
push @ee => $h{$r}{$n};
которая заносит частоты слов(3,1,1 как было выше в примере) в текущей строке. Дальше идет сама exists и после неё разбираемся с весом повторяющихся слов и весом полных совпадений. Т.е. должно быть так, чтобы полное совпадение фразы имело большее значение, нежели чем неполное совпадение + пара повторов. Но функция федет себя по хитрому, допустим, если нужно найти специализированную информацию типа "Хеш хешей хешей хешей хешей массивов", то вес повторений слов будет больше, т.е. вклад члена $ee[0]-1(разница в единицах на случай непреднамеренного повтора) больше, чем $u. В то-же время частота повторений может запросто вывести наверх ссылку с словом, которому посвящен текст. Т.е. некий баланс для фраз, повторений и одиночных слов.