38

I created an autocomplete field using JQueryUI and I've stored my data in a flat doc. I can read the values into an array... but I would like to be able to return the alphabetic matches based on the user input. So if the array contains [orange,blue,green,red,pink,brown,black] and the user types bl then I only return [blue,black].

Looking at array_diff() but without complete matches on the entire value of the array, I'm not sure how to use it... maybe a regular expression thrown in? My two weakest skills array manipulation and regex Thanks for the help!

Ecropolis
  • 2,005
  • 2
  • 22
  • 27
  • did you look at the autocomplete 'xml data parsed once' example (http://jqueryui.com/demos/autocomplete/#xml)? You may find it easier and more efficient to change your data storage format. – dnagirl Apr 27 '11 at 18:52

4 Answers4

67

You don't need to use array_filter and a custom / lambda function, preg_grep does the trick:

$input = preg_quote('bl', '~'); // don't forget to quote input string!
$data = array('orange', 'blue', 'green', 'red', 'pink', 'brown', 'black');

$result = preg_grep('~' . $input . '~', $data);
Alix Axel
  • 151,645
  • 95
  • 393
  • 500
16

array_filter(), with a callback filtering function based on stripos(), should do the trick.


For example, if the input is stored in $input, and your array in $data :

$input = 'bl';
$data = array('orange', 'blue', 'green', 'red', 'pink', 'brown', 'black');

Filtering to keep only the words that contain $input (no matter where in the string) could be done this way :

$result = array_filter($data, function ($item) use ($input) {
    if (stripos($item, $input) !== false) {
        return true;
    }
    return false;
});

var_dump($result);

And, here, you'd get :

array
  1 => string 'blue' (length=4)
  6 => string 'black' (length=5)


Changing the filtering callback, you can :

  • Test if the string begins with the input -- testing if the value returned by stripos() is === 0
  • Use a case-sensitive matching function, like strpos()
Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
  • 1
    this is the right solution if you want to maintain key values and be able to use non integer keys – murtho May 14 '19 at 12:22
2

You could simply iterate through the array to look for all strings that start with the given letters. Having the list of words already sorted in your flat file would probably speed things up. I think this works pretty well:

$input = strtolower("bl"); //from the user
$colors = array("black", "blue", "brown", "..."); //already sorted alphabetically
$matches = array();
foreach ($colors as $c){
  if (strpos($c, $input) === 0){
    //if $c starts with $input, add to matches list
    $matches[] = $c;
  } else if (strcmp($input, $c) < 0){
    //$input comes after $c in alpha order
    //since $colors is sorted, we know that we won't find any more matches
    break;
  }
}
Michael
  • 34,873
  • 17
  • 75
  • 109
2

like %search%

function like(array $arr, string $patron): array
    {
        return array_filter($arr, static function (mixed $value) use ($patron): bool {
            return 1 === preg_match(sprintf('/^%s$/i', preg_replace('/(^%)|(%$)/', '.*', $patron)), $value);
        });
    }

test

$b=['a'=>'peter','b'=>'patter','c'=>'alter','d'=>'all'];
var_dump(like($b,'%ter'));// ['a'=>'peter','b'=>'patter','c'=>'alter']
var_dump(like($b,'al%'));//['c'=>'alter','d'=>'all']