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!

1
  • did you look at the autocomplete 'xml data parsed once' example (jqueryui.com/demos/autocomplete/#xml)? You may find it easier and more efficient to change your data storage format. Commented Apr 27, 2011 at 18:52

4 Answers 4

68

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);
Sign up to request clarification or add additional context in comments.

15 Comments

Your answer led me to preg_grep(). Changed preg_filter() to that and removed null and worked like a charm; thanks!
@Ecropolis: I think the correct syntax in this case is preg_filter('~' . $input . '~', '$0', $data);.
@EmilioGort: Sure, just add an i modifier after the last ~ delimiter.
@MichaelRopy: $result = preg_grep('~^' . $input . '~', $data);
Great answer. Every time this answer comes up in google when I search for array filters.
|
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()

1 Comment

this is the right solution if you want to maintain key values and be able to use non integer keys
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;
  }
}

Comments

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']

1 Comment

What if the input is an array? Please help, thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.