レーベンシュタイン距離とマッチ率を同時に出したい
タイトル通り、EclipseのPHPで任意の単語同士のリーベンシュタイン距離、それらのマッチ率を出したいのですが、以下のところまで出来たのですがどん詰り状態で困っています。
転載が長いので先に質問を書いておきます。
最終的な形としては、
・「リーベン距離○=○ 、 マッチ率 AとBは○%マッチ」のような形で一緒に表示させたい。(できれば1~など改行ごとに番号もふりたい)
・マッチ率の表示もマルチバイトのエンコードで文字化けさせないようにしたい。
…です。
現段階では、リーベン距離はしっかり表示されますが、出力後のリーベン距離の数字それぞれの間に、文字化けしたマッチ率が入り込んでしまいます。
稚拙な質問の仕方で恐縮ですが、解決法をご存じの方がいらっしゃいましたら御教授のほどよろしくお願い申し上げます。
(以下転載)
<?php
* マルチバイト文字列、英数字の混じった文字列を1文字ずつ配列に分割
function mbStringToArray($string, $encoding = 'UTF-8') {
$arrayResult = array();
while ($iLen = mb_strlen($string, $encoding)) {
array_push($arrayResult, mb_substr($string, 0, 1, $encoding));
$string = mb_substr($string, 1, $iLen, $encoding);
}
return $arrayResult;
}
* レーベンシュタイン距離を求める(マルチバイト文字対応)
function LevenshteinDistance($str1, $str2, $costReplace = 2, $encoding = 'UTF-8') {
$count_same_letter = 0;
$d = array();
$mb_len1 = mb_strlen($str1, $encoding);
$mb_len2 = mb_strlen($str2, $encoding);
$mb_str1 = mbStringToArray($str1, $encoding);
$mb_str2 = mbStringToArray($str2, $encoding);
for ($i1 = 0; $i1 <= $mb_len1; $i1++) {
$d[$i1] = array();
$d[$i1][0] = $i1;
}
for ($i2 = 0; $i2 <= $mb_len2; $i2++) {
$d[0][$i2] = $i2;
}
for ($i1 = 1; $i1 <= $mb_len1; $i1++) {
for ($i2 = 1; $i2 <= $mb_len2; $i2++) {
//$cost = ($str1[$i1 - 1] == $str2[$i2 - 1]) ? 0 : 1;
if ($mb_str1[$i1 - 1] === $mb_str2[$i2 - 1]) {
$cost = 0;
$count_same_letter++;
} else {
$cost = $costReplace; //置換
}
$d[$i1][$i2] = min($d[$i1 - 1][$i2] + 1, //挿入
$d[$i1][$i2 - 1] + 1, //削除
$d[$i1 - 1][$i2 - 1] + $cost);
}
}
return $d[$mb_len1][$mb_len2];
return array('distance' => $d[$mb_len1][$mb_len2], 'count_same_letter' => $count_same_letter);
}
*求めたいリーベン距離のテキストのサンプル(長いので4つだけ書き出します)
$text = array(
array('ath', '八'),
array('ath', 'oktōu'),
array('ath', 'eight'),
array('ath', 'acht'),
);
foreach($text as $row) {
echo levenshtein($row[0], $row[1]);
echo ' = ';
echo LevenshteinDistance($row[0], $row[1]);
echo '<br/>';
*求めたい単語のマッチ率を求める(マルチバイト対応のやり方が不明のためこのままだと文字化けする)
$Key = "ath";
$words = array(
'八',
'oktōu',
'eight',
'acht',
);
$matches = array();
foreach ($words as $word) {
$c = similar_text($Key, $word, $percent);
echo $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')';
echo "<br/> ";
$matches[intval($percent)] = $word;
}
}
?>
(転載終わり)
これらを実効出力すると、
3 = 4
ath 縺ィ 蜈ォ is 0% similar(0)
ath 縺ィ oktナ講 is 22% similar(1)
ath 縺ィ eight is 25% similar(1)
ath 縺ィ acht is 57% similar(2)
5 = 6
ath 縺ィ 蜈ォ is 0% similar(0)
ath 縺ィ oktナ講 is 22% similar(1)
ath 縺ィ eight is 25% similar(1)
ath 縺ィ acht is 57% similar(2)
4 = 6
ath 縺ィ 蜈ォ is 0% similar(0)
ath 縺ィ oktナ講 is 22% similar(1)
ath 縺ィ eight is 25% similar(1)
ath 縺ィ acht is 57% similar(2)
2 = 3
ath 縺ィ 蜈ォ is 0% similar(0)
ath 縺ィ oktナ講 is 22% similar(1)
ath 縺ィ eight is 25% similar(1)
ath 縺ィ acht is 57% similar(2)
と、リーベンは大丈夫でも他がめちゃめちゃになってしまっている状況です。
恐縮ですが、御教授のほど、よろしくお願い申し上げます。
お礼
回答ありがとうございます。 ご指摘を参考に、素直にarray($a, $b);し、foreach ($text as $row) の[0][1]の指定をやめ、utf-8で書き直しました。 sjisに変換していたのは、日本語文字部分が文字化けするための対策だったのですが、改めてutf-8で書きなおして解決しました。 御助言のおかげでここ数日間、ヒントにいろいろ調べながら勉強することが出来ました。 ありがとうございます。