Reputation: 1558
I been reading and testing some examples in php levenshtein. Comparing $input to $words outputs comparing
$input = 'hw r u my dear angel';
// array of words to check against
$words = array('apple','pineapple','banana','orange','how are you',
'radish','carrot','pea','bean','potato','hw are you');
outputs
Input word: hw r u my dear angel
Did you mean: hw are you?
comparing, remove hw are you in the array.
$input = 'hw r u my dear angel';
// array of words to check against
$words = array('apple','pineapple','banana','orange','how are you',
'radish','carrot','pea','bean','potato');
in the second removing hw are you in the array outputs
Input word: hw r u my dear angel
Did you mean: orange?
where in similar_text()
echo '<br/>how are you:'.similar_text($input,'how are you');
echo '<br/>orange:'.similar_text($input,'orange');
echo '<br/>hw are you:'.similar_text($input,'hw are you');
how are you:6
orange:5
hw are you:6
on second compare why does it output orange when how are you has also 6 similar text like hw are you? Is there any way to improve or better method about this?ALso im saving all the posible input on the database. should i query it and store in array
then use foreach
to get levenshtein distance
? but that would be slow if a have millions.
CODE
<?php
// input misspelled word
$input = 'hw r u my dear angel';
// array of words to check against
$words = array('apple','pineapple','banana','orange','how are you',
'radish','carrot','pea','bean','potato','hw are you');
// no shortest distance found, yet
$shortest = -1;
$closest = closest($input,$words,$shortest);
echo "Input word: $input<br/>";
if ($shortest == 0) {
echo "Exact match found: $closest\n";
} else {
echo "Did you mean: $closest?\n";
}
echo '<br/><br/>';
$shortest = -1;
$words = array('apple','pineapple','banana','orange','how are you',
'radish','carrot','pea','bean','potato');
$closest = closest($input,$words,$shortest);
echo "Input word: $input<br/>";
if ($shortest == 0) {
echo "Exact match found: $closest\n";
} else {
echo "Did you mean: $closest?\n";
}
echo '<br/><br/>';
echo 'Similar text';
echo '<br/>how are you:'.similar_text($input,'how are you');
echo '<br/>orange:'.similar_text($input,'orange');
echo '<br/>hw are you:'.similar_text($input,'hw are you');
function closest($input,$words,&$shortest){
// loop through words to find the closest
foreach ($words as $word) {
// calculate the distance between the input word,
// and the current word
$lev = levenshtein($input, $word);
// check for an exact match
if ($lev == 0) {
// closest word is this one (exact match)
$closest = $word;
$shortest = 0;
// break out of the loop; we've found an exact match
break;
}
// if this distance is less than the next found shortest
// distance, OR if a next shortest word has not yet been found
if ($lev <= $shortest || $shortest < 0) {
// set the closest match, and shortest distance
$closest = $word;
$shortest = $lev;
}
}
return $closest;
}
?>
Upvotes: 3
Views: 9213
Reputation: 1558
Found something.. but uses mysql http://www.artfulsoftware.com/infotree/queries.php#552 I think this is much better than processing it on php since my data are stored in database.
CREATE FUNCTION levenshtein( s1 VARCHAR(255), s2 VARCHAR(255) )
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT;
DECLARE s1_char CHAR;
-- max strlen=255
DECLARE cv0, cv1 VARBINARY(256);
SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0;
IF s1 = s2 THEN
RETURN 0;
ELSEIF s1_len = 0 THEN
RETURN s2_len;
ELSEIF s2_len = 0 THEN
RETURN s1_len;
ELSE
WHILE j <= s2_len DO
SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1;
END WHILE;
WHILE i <= s1_len DO
SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1;
WHILE j <= s2_len DO
SET c = c + 1;
IF s1_char = SUBSTRING(s2, j, 1) THEN
SET cost = 0; ELSE SET cost = 1;
END IF;
SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost;
IF c > c_temp THEN SET c = c_temp; END IF;
SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1;
IF c > c_temp THEN
SET c = c_temp;
END IF;
SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1;
END WHILE;
SET cv1 = cv0, i = i + 1;
END WHILE;
END IF;
RETURN c;
END;
And a helper function:
CREATE FUNCTION levenshtein_ratio( s1 VARCHAR(255), s2 VARCHAR(255) )
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE s1_len, s2_len, max_len INT;
SET s1_len = LENGTH(s1), s2_len = LENGTH(s2);
IF s1_len > s2_len THEN
SET max_len = s1_len;
ELSE
SET max_len = s2_len;
END IF;
RETURN ROUND((1 - LEVENSHTEIN(s1, s2) / max_len) * 100);
END;
but i don't know why this cause error You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 5
Upvotes: 1
Reputation: 25389
First of all it doesn't matter what outputs similar_text()
, because it uses another algorithm to calculate similarity between strings.
Lets try to understand why levenstein()
thinks, that hw r u my dear ange is closer to orange than to 'how are you. Wikipedia has a good definition of what Levenstein distance is.
Informally, the Levenshtein distance between two words is the minimum number of single-character edits (insertion, deletion, substitution) required to change one word into the other.
Now lets count how many edits we have to do to change hw r u my dear angel into orange.
So it takes 1 + 1 + 12 + 1 = 15
edits total to change hw r u my dear angel into orange.
And here is transformation of hw r u my dear angel into how are you.
Total 1 + 7 + 2 + 1 + 5 = 16
edits. So as you can see in terms of Levinstein distance orange is closer to hw r u my dear angel ;-)
Upvotes: 9