dポイントプレゼントキャンペーン実施中!

タイトル通り、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)

と、リーベンは大丈夫でも他がめちゃめちゃになってしまっている状況です。

恐縮ですが、御教授のほど、よろしくお願い申し上げます。

A 回答 (2件)

http://oshiete.goo.ne.jp/qa/7084707.html

> 縺ィ 蜈ォ

この化け方は、UTF-8 の文字列を Shift_JIS とみなして表示しているときに
見かけます。

Eclipse を使ったことがないので、実行結果がどこに出てくるのかわかりませんが
もしWebブラウザで見ているなら、ツールとかオプションとかでエンコードを
Shift_JIS に変更すれば、文字化けせずに表示されないでしょうか?


> echo $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')';

ここで、出力に先立って Shift_JIS に変換してやれば、とりあえず解消するように思います。

$buf = $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')';
echo mb_convert_encoding($buf, 'SJIS', 'UTF-8');

ただし o の上に棒のある文字はうまく表示できないかもしれません。


また、出力内容の文字コードが UTF-8 であるにもかかわらず、
HTTPレスポンスヘッダや HTMLのmetaタグの Content-Type で
charset=Shift_JIS を宣言している、といった食い違いが考えられるので
そちらを charset=UTF-8 にしてもいいかと思います。

この回答への補足

回答ありがとうございます。

早速、全て試しました。
エンコードは全て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は○%マッチ」と各々で見栄え良く表示させる方法を御教授いただけたら幸いに存じ上げます。

(後者は、レーベン全ての出力結果の表示後に、マッチ率全て出力結果の表示と、別途分けて出力することしかできないのであれば、それでも構いません。もしできるならまとめて表示させたいです。
アクセント付き文字のエンコードについてだけでも、御存じの方がいらっしゃいましたら補足回答のほど、よろしくお願い申し上げたいです。)

補足日時:2011/10/21 15:22
    • good
    • 0

お返事が遅くなってしまいすみません。


UTF-8 であればアクセント付文字を表示できそうです。

>$buf = $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')';
>echo mb_convert_encoding($buf, 'SJIS', 'UTF-8');

この SJIS への変換は止めて、元に戻しましょう。


echo $Key. ' と ' .$word. ' は ' .intval($percent). '% マッチ('.$c.')';



そして、ブラウザへの出力を始める前、
すなわち、

foreach($text as $row) {

の前あたりに、

header('Content-Type: text/html; charset=utf-8');

を書いてみてください。
    • good
    • 0
この回答へのお礼

改めてありがとうございます!

そしてこちらこそお礼までの期間が空いて、誠に申し訳ございませんでした。

おかげ様で、無事アクセント文字も読み込むことができました!
本当に助かりました!

重ねまして御礼申し上げます!

お礼日時:2011/11/10 02:58

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!