Fuzzy String Search Using Levenshtein Distance
Lowercases both query and each candidate, computes levenshtein() distance, then overrides to 0 if the query is a substring. Filters by maxDistance, computes a percentage similarity, and sorts results by distance ascending.
edit_note
PHP Code Editor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
/**
* Fuzzy search using Levenshtein distance.
* Returns matches sorted by similarity, filtered by max allowed distance.
*/
function fuzzySearch(string $query, array $haystack, int $maxDistance = 3): array
{
$query = strtolower($query);
$results = [];
foreach ($haystack as $item) {
$lower = strtolower($item);
$distance = levenshtein($query, $lower);
// Also check if query is a substring (distance 0 for exact prefix)
if (str_contains($lower, $query)) {
$distance = 0;
}
if ($distance <= $maxDistance) {
$results[] = [
'item' => $item,
'distance' => $distance,
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
settingsPHP Version
panorama_fish_eye
7.2
panorama_fish_eye
7.4
panorama_fish_eye
8.0
panorama_fish_eye
8.1
task_alt
8.2
panorama_fish_eye
8.3
panorama_fish_eye
8.4
panorama_fish_eye
8.5
terminal
Execution Result
play_circle_outline
Ready to execute
Click the "Run Script" button to see the output here
article
Description
Fuzzy search tolerates typos by measuring how many single-character edits (insertions, deletions, substitutions) separate the query from each candidate. This is what PHP’s built-in levenshtein() computes. The function lowercases both sides for case-insensitive comparison. If the query is a substring of a candidate, the distance is forced to 0 regardless of what levenshtein returns, so prefix matches always rank first.
Candidates with a distance above maxDistance are discarded. The remaining matches are annotated with a percentage similarity score computed as 1 - distance / max(strlen(query), strlen(candidate)) and sorted by distance ascending so the closest matches appear first.
<?php
/**
* Fuzzy search using Levenshtein distance.
* Returns matches sorted by similarity, filtered by max allowed distance.
*/
function fuzzySearch(string $query, array $haystack, int $maxDistance = 3): array
{
$query = strtolower($query);
$results = [];
foreach ($haystack as $item) {
$lower = strtolower($item);
$distance = levenshtein($query, $lower);
// Also check if query is a substring (distance 0 for exact prefix)
if (str_contains($lower, $query)) {
$distance = 0;
}
if ($distance <= $maxDistance) {
$results[] = [
'item' => $item,
'distance' => $distance,
'similarity' => round((1 - $distance / max(strlen($query), strlen($lower))) * 100),
];
}
}
usort($results, fn($a, $b) => $a['distance'] <=> $b['distance']);
return $results;
}
// Demo: command name typo correction
$commands = [
'migrate', 'migrate:fresh', 'migrate:rollback', 'make:model',
'make:controller', 'make:migration', 'route:list', 'route:clear',
'cache:clear', 'config:cache', 'queue:work', 'queue:listen',
'serve', 'tinker', 'test',
];
$typos = ['migarte', 'mak:model', 'rote:list', 'cach:clear', 'tinkr'];
foreach ($typos as $typo) {
echo "Input: \"$typo\"\n";
$matches = fuzzySearch($typo, $commands, maxDistance: 4);
foreach (array_slice($matches, 0, 3) as $m) {
printf(" -> \"%s\" (distance: %d, similarity: %d%%)\n",
$m['item'], $m['distance'], $m['similarity']);
}
echo "\n";
}
Comments
No comments yet
Be the first to share your thoughts!