Определение дистанции по Джаро-Винклеру


function JaroWinkler($s1,$s2,$p=0.1)
{
    if (($s1=='') or ($s2=='')) return 0;
    if ($s1==$s2) return 1;

    $emax = intval(floor(max(mb_strlen($s1), mb_strlen($s2))/2)-1);
    $matching = 0;
    $L1 = mb_strlen($s1);
    $L2 = mb_strlen($s2);
    $b1 = array_fill(0,$L1,false);
    $b2 = array_fill(0,$L2,false);
    for($i=0;$i<$L1;$i++) {
        $low = ($i>=$emax)? $i-$emax : 0;
        $high = (($i+$emax) <= ($L2-1))? ($i+$emax) : ($L2-1);

        for ($j = $low; $j <= $high; $j++) {
            if (($b1[$i]!=true) && ($b2[$j]!=true) && (mb_substr($s1,$i,1)===mb_substr($s2,$j,1))) {
                $matching++;
                $b1[$i] = true; $b2[$j] = true;
                break;
            }
        } // for $j
    } // for $i
    if ($matching==0) return 0;
    $transposition = 0; $k = 0;

    for($i=0; $i < $L1; $i++) {
        if ($b1[$i] == true) {
            for ($j=$k; $j < $L2; $j++) {
                if ($b2[$j] == true) {
                    $k = $j + 1;
                    break;
                }
            } // for $j
            if (mb_substr($s1,$i,1) != mb_substr($s2,$j,1)) {
                $transposition++;
            }
        }
    } // for $i

    $distance = ($matching / $L1 + $matching / $L2 + ($matching - ($transposition / 2)) / $matching) / 3;
    $l = 0;
    $p = 0.1;

    if ($distance > 0.7) {
      while ((mb_substr($s1,$l,1) == mb_substr($s2,$l,1)) && ($l < 4)) $l++;
    }

    $distance += $l * $p * (1 - $distance);

    return $distance;

}

$a = 'Дугая';
$b = 'Вопреки';

echo JaroWinkler($a,$b);