4

I am trying to search a list of files and only perform work on the files that have names that contain a few values in an array. I am hoping to not have to loop through the array each time I have a new filename.
ala-

$needle = array('blah', 'bleh');
foreach($file_list as $file)
{
    foreach($needle as $need)
       if(strstr($file, $need) !== false)
          {
             // do something...
          }
}

I just need to know if one of the strings in the array is in the filename, not the location of the string.

I would like to use something similar to strstr() but it does not allow an array to be used as the needle.

i.e.-

if(strstr($haystack, array('blah', 'bleh')))
{
   // do something...
}

I would prefer to stay away from regular expressions, it seems to be a sledge for a hammer's job. any ideas?

3
  • use a break 2; when you find the first occurrence php.net/manual/en/control-structures.break.php Commented Dec 28, 2010 at 16:28
  • actually is the problem that you don't want to loop the entire array or that you can't pass an array as a needle? Commented Dec 28, 2010 at 16:38
  • I don't want to loop through the array, and I can't pass the needle as an array to strstr() Commented Dec 28, 2010 at 16:40

6 Answers 6

7

IMO it is fine to use regular expressions here:

$pattern  = '/' . implode('|', array_map('preg_quote', $needle)) . '/i';

foreach($file_list as $file) {
    if(preg_match($pattern, $file)) {
    // do something
    }
}

Reference: preg_quote


Here is a more "creative" way to do it (but it uses internal loops and is very likely slower, as you actually loop several times over the array):

function cstrstr($haystack, $needle) {
    return strstr($haystack, $needle) !== false;
}

foreach($file_list as $file) {
    if(array_sum(array_map('cstrstr', 
                       array_pad(array($file), count($needle), $file), 
                       $needle))) {
        // do something
    }
}

But the advantages with the regex should be obvious: You have to create the pattern only once whereas in the "funny" solution you always have to create an array of length count($needle) for every $file.

Sign up to request clarification or add additional context in comments.

3 Comments

why to use regex if it is possible to simply use strstr() or in_array() ? it will increase the complexity of algorithm.
@s3v3n: Yes you can loop and use strstr() and break when you found it. That is another solution. But in_array only works if the name of the file is equal to a word contained in the array. I understood the question in the way that the filename can contain words in the array...
Actually I got an idea. I'll post it now as an answer.
1

Patrick,

You can use in_array(). Example:

foreach($file_list as $file){

   if(in_array($file, $needle)){
     //--------------
     // Needle found
   }
}

You can find more examples here: http://php.net/manual/en/function.in-array.php

3 Comments

I'm not trying to match the entire filename though, does in_array() work on partial strings as well?
@Patrick, could you provide an example of the file names you're working with? It may be easier to apply a specific naming convention to your files in order to get in_array() to work correctly. If you're goal is to not iterate through the array each time, in_array() is the best way to go.
@OV Web Solutions, it will generally be file extension based, but I may have to do other conventions in the future.
1

This will perform an action on all the files that contain all the needles inside their name

// Loop through files
foreach($files as $file){
    foreach($needles as $needle){
        // if filename does not contain this needle
        if(strpos($file, $needle) === false)
            continue 2; // skip to next file
    }
    // this file matches criteria. do smth on this file
}

Comments

0

in_array may work just fine, however it would require exact matches in your needle array.

You could implode the array with some hash-string, and use the result with strstr or strposstr variant returns the first occurrence, pos only the position of the first occurrence— Make sure to have a very unique string, with both an uncommon prefix and suffix. This is rather a quick and dirty approach, but it may just work in your situation.

EDIT I was just thinking, why don't you want to use a loop? It'll be much faster than concatenating all elements from an array. Your question if there is a function to find partial matches using a reference array: it's not build-in, so you'd better use your own loop (or implement some function to do it, using a loop of course)

1 Comment

Well, let's say you have arrray('somevalue1', 'somevalue2') and the file value1. Using implode with :: would give somevalue1::somevalue2 and then strpos($imploded_array, 'value1') would return non-FALSE.
0
if( strstr( implode( " ", $array ), $search )  { //found   }

But a function with loop and return when found is faster and less memory consuming.

function searchArrayFast( $array, $search ) { foreach ( $array as $a ) { if( strstr( $a, $search)){ return true; } } return false; }

Comments

0

Do not use preg_match() if you only want to check if one string is contained in another string. Use strpos() instead as it will be faster. http://php.net/manual/en/function.preg-match.php

$needle = array('blah', 'bleh');

foreach ($file_list as $file) {

    $result = $this->searchStrpos($file, $needle);

        if ($result !== false) {

            // do something...
        }
    }

/**
 * 
 * @param String $string String search
 * @param mixed $needle
 * @param Boolean $onlyFirst return true but 
 * @return Boolean Return boolean for search
 */
private function searchStrpos($string, $needle, $onlyFirst = true) {
    if (is_array($needle)) {
        foreach ($needle as $item) {
            $result = strpos($string, $item);
            if ($result !== false && $onlyFirst) {
                break;
            }
        }
    } else {
        $result = strpos($string, $needle);
    }

    return $result;
}

Comments

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.