Skip to content

Commit

Permalink
ready
Browse files Browse the repository at this point in the history
  • Loading branch information
claudemyburgh committed Jul 20, 2024
1 parent f1ae598 commit c8b2b1a
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
27 changes: 26 additions & 1 deletion src/FuzzySearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,29 @@

namespace Designbycode\FuzzySearch;

class FuzzySearch {}
class FuzzySearch {

private $texts;
private $levenshteinDistance;

public function __construct(array $texts) {
$this->texts = $texts;
$this->levenshteinDistance = new LevenshteinDistance();
}

public function search($query, $maxDistance = 2): array
{
$query = strtolower($query); // Convert query to lowercase
$results = array();
foreach ($this->texts as $text) {
$textLowercase = strtolower($text); // Convert text to lowercase
$distance = $this->levenshteinDistance->calculate($query, $textLowercase);
if ($distance <= $maxDistance) {
$results[] = $text; // Store original text (with original case)
}
}
return $results;
}


}
50 changes: 50 additions & 0 deletions src/LevenshteinDistance.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Designbycode\FuzzySearch;

class LevenshteinDistance {
/**
* Calculate the Levenshtein distance between two strings.
*
* The Levenshtein distance is a measure of the minimum number of single-character edits
* (insertions, deletions or substitutions) required to change one word into the other.
*
* @param string $str1 The first string.
* @param string $str2 The second string.
* @return int The Levenshtein distance between the two strings.
*/
public static function calculate(string $str1, string $str2): int
{
// Create a 2D array to store the distances between substrings of $str1 and $str2
$distanceMatrix = array();

// Initialize the first row and column of the matrix
$str1Length = strlen($str1);
$str2Length = strlen($str2);
for ($i = 0; $i <= $str1Length; $i++) {
$distanceMatrix[$i][0] = $i; // Distance from empty string to $str1 substrings
}
for ($j = 0; $j <= $str2Length; $j++) {
$distanceMatrix[0][$j] = $j; // Distance from empty string to $str2 substrings
}

// Iterate through the characters of $str1 and $str2
for ($i = 1; $i <= $str1Length; $i++) {
for ($j = 1; $j <= $str2Length; $j++) {
// Calculate the cost of substitution (0 if characters match, 1 if they don't)
$substitutionCost = ($str1[$i - 1] == $str2[$j - 1]) ? 0 : 1;

// Calculate the minimum distance between the current substrings
$insertionDistance = $distanceMatrix[$i - 1][$j] + 1; // Insert a character into $str1
$deletionDistance = $distanceMatrix[$i][$j - 1] + 1; // Delete a character from $str1
$substitutionDistance = $distanceMatrix[$i - 1][$j - 1] + $substitutionCost; // Substitute a character in $str1

// Choose the minimum distance
$distanceMatrix[$i][$j] = min($insertionDistance, $deletionDistance, $substitutionDistance);
}
}

// Return the Levenshtein distance between the entire strings
return $distanceMatrix[$str1Length][$str2Length];
}
}
31 changes: 31 additions & 0 deletions tests/FuzzySearchTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

use Designbycode\FuzzySearch\FuzzySearch;

test('search returns similar matches', function () {
$index = ['apple', 'banana', 'orange', 'grape', 'pear'];
$fuzzySearch = new FuzzySearch($index);
$results = $fuzzySearch->search('aple');
expect($results)->toEqual(['apple']);
});

test('search returns no results for non-existent query', function () {
$index = ['apple', 'banana', 'orange', 'grape', 'pear'];
$fuzzySearch = new FuzzySearch($index);
$results = $fuzzySearch->search('xyz');
expect($results)->toEqual([]);
});

test('search returns exact match', function () {
$index = ['apple', 'banana', 'orange', 'grape', 'pear'];
$fuzzySearch = new FuzzySearch($index);
$results = $fuzzySearch->search('apple');
expect($results)->toEqual(['apple']);
});

test('search is case-insensitive', function () {
$index = ['Apple', 'banana', 'orange', 'grape', 'pear'];
$fuzzySearch = new FuzzySearch($index);
$results = $fuzzySearch->search('aPpLe');
expect($results)->toEqual(['Apple']);
});

0 comments on commit c8b2b1a

Please sign in to comment.