タイトル通り、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)
と、リーベンは大丈夫でも他がめちゃめちゃになってしまっている状況です。
恐縮ですが、御教授のほど、よろしくお願い申し上げます。
補足
回答ありがとうございます。 早速、全て試しました。 エンコードは全てUTF-8に設定してありました。 またWebプラウザはShift_JISに設定しました。(むしろ下記出力後に自動的に設定されたような気がしました) >$buf = $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')'; >echo mb_convert_encoding($buf, 'SJIS', 'UTF-8'); マッチ率にこちらを追加したところ、見事に「縺ィ 蜈ォ」の文字化けが直って、正常に表示されました。 本当にありがとうございます。 しかし、仰った通り、単語の上に記号のある文字はうまく表示できませんでした。 「ō å š ë ā」などのアクセント付き文字は「?」と表示されます。 athとoktōuならば、 「ath と okt?u は 22% マッチ(1)」 という感じです。 (アクセント付き文字↓これらのことですね。) アクセント付き文字の変換表 0.11 http://cosmoshouse.com/tools/acc-conv-j.htm 引き続いて恐縮ではございますが、後見の方ためにも、これらの文字を正常に表示させる方法と、 レーベン距離とマッチ率を「レーベン距離○=○ 、 マッチ率 AとBは○%マッチ」と各々で見栄え良く表示させる方法を御教授いただけたら幸いに存じ上げます。 (後者は、レーベン全ての出力結果の表示後に、マッチ率全て出力結果の表示と、別途分けて出力することしかできないのであれば、それでも構いません。もしできるならまとめて表示させたいです。 アクセント付き文字のエンコードについてだけでも、御存じの方がいらっしゃいましたら補足回答のほど、よろしくお願い申し上げたいです。)