2

I am attempting to search an array using preg_grep for any values which contain all the words listed in my pattern, in any order.

Assuming the words I want to search for are as follows: apple pear banana

I have tried:

$result = preg_grep("/(apple|pear|banana)/i", $array);

Which returns strings that contain any of the three words

$result = preg_grep("/(apple.*pear.*banana)/i", $array);

Which returns strings that contain all 3, but they must be in order.

How to perform unordered preg_grep?

Barmar
  • 741,623
  • 53
  • 500
  • 612
user984976
  • 1,314
  • 1
  • 12
  • 21

2 Answers2

4

Doing a "match all" in a single regexp is difficult -- you need to enumerate all possible orders, which is O(n!). Instead, use array_filter():

array_filter($array, function($x) {
    return preg_match('/apple/', $x) && preg_match('/pear/', $x) && preg_match('/banana/', $x);
});
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • thanks for your answer. I've not come across the && operator between arrays before, how does this work? Also, how could this be extended to use an array of words? – user984976 May 30 '13 at 03:15
  • I'm not using it between arrays. `preg_match()` returns true or false, not an array. – Barmar May 30 '13 at 03:27
  • Sorry, I totally misread that I thought you were still using preg_grep. Apologies for the dumb question. – user984976 May 30 '13 at 03:30
  • I have trouble trying to extend this to work across an array of 'words' (which I realise is outside the scope of the original question), because there does not seem to be an easy way to pass the array to the callback function, except creating another class as outlined: http://stackoverflow.com/questions/5482989/php-array-filter-with-arguments – user984976 May 30 '13 at 03:40
  • You should be able to do it with a closure and the `use` option. – Barmar May 30 '13 at 03:55
3

you can also try using a look ahead pattern..

preg_grep("/(?=.*apple)(?=.*pear)(?=.*banana).*/",$array);

dshu610
  • 191
  • 3
  • I thought lookahead didn't allow variable-length patterns. – Barmar May 30 '13 at 03:29
  • I've always used these types of patterns for validating password formats.. (i.e. at least 1 number, 1 capital letter etc..) – dshu610 May 30 '13 at 03:46
  • 1
    I have chosen this solution because I profiled both this and Barmar's solution (using xdebug) and found that for my list of 4000 strings and 3 search words on average this executed 4x faster than performing array_filter and multiple greps. – user984976 May 30 '13 at 04:13