search string with array of values with PHP - php

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?

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.

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

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
}

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 strpos —str 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)

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;
}

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;
}

Related

how to check presence of certain character in a variable using php

Am using code below to check presence of certain character via php and it works fine.
with code below, I can check if character a is presence in the variable and is working.
$mystring = 'my food is okay. its delicious';
$findme = 'a';
$pos = strpos($mystring, $findme);
if ($pos !== false) {
echo 'data found';
}
Here is my issue: I need to check the also presence of multiple characters like m,e,s etc. any idea on how to achieve that.
There are many ways to do this, from using multiple strpos to comparisons after a str_replace. Here we can split the string into an array and calculate the intersection with another array:
$mystring = 'my food is okay. its delicious';
$findme = ['m', 'e', 's'];
Check for ANY of the characters in the array:
if(array_intersect($findme, str_split($mystring))) {
echo "1 or more found";
}
Check for ALL of the characters in the array:
if(array_intersect($findme, str_split($mystring)) == $findme) {
echo "all found";
}
And for fun, run the array through a callback and filter it based upon whether it is in the string. This will check for ANY:
if(array_filter($findme, function($v) use($mystring) {
return strpos($mystring, $v) !== false;
}))
{
echo "1 or more found";
}
This will check for ALL:
if(array_filter($findme, function($v) use($mystring) {
return strpos($mystring, $v) !== false;
}) == $findme)
{
echo "all found";
}
Another way to do this is with trim.
$mystring = 'my food is okay. its delicious';
$findme = 'ames';
$any = trim($findme, $mystring) != $findme;
$all = !trim($findme, $mystring);
This function will do the trick for you:
/**
* Takes an array of needles and searches a given string to return all
* needles found in the string. The needles can be words, characters,
* numbers etc.
*
* #param array $needles
* #param string $haystack
* #return array|null
*/
function searchString(array $needles, string $haystack): ?array
{
$itemsFound = [];
foreach($needles as $needle) {
if (strpos($haystack, $needle) !== false) {
$itemsFound[] = $needle;
}
}
return $itemsFound;
}
https://3v4l.org/5oXGp

List all elements in array containing certain word in PHP

I'm attempting to make a search feature for my website using PHP. Right now, I have this code to create an array of all files in a directory, which works just fine, but I've hit a snag with my next step. I want it to now list all elements in that array that contain a certain word (the users search), this way I can do something with them later in HTML. My idea was to make a loop that runs strpos for each element and list only the ones it finds matches for. I've tried that, but it always gave me nothing. This is my honest attempt:
<?php
$search = "Pitfall";
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.')) as $filename)
{
if ($filename->isDir()) continue;
foreach ($filename as &$result)
{
$pos = strpos($result, $search);
if ($pos === true) {
echo "$result\n";
}
}
}
?>
Thank you for any help
I think your issue is with your conditional:
if ($pos === true)
strpos() does not return true. It returns the position of the string or false. See docs. You could instead use:
if ($pos !== false)
Edited:
The RecusiveIteratorIterator does not return a string. It returns an object. Here I am typecasting the object so that it gets the correct filename. From there, you don't need to iterate over again, as this is just a string at this point.
$search = "wp-config";
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.')) as $filename)
{
$filename = (string) $filename;
if (is_dir($filename)) continue;
$pos = strpos($filename, $search);
if ($pos !== false) {
echo "$filename <br />";
}
}

Retrieve word from string

I have this code:
$getClass = $params->get('pageclass_sfx');
var_dump($getClass); die();
The code above returns this:
string(24) "sl-articulo sl-categoria"
How can I retrieve the specific word I want without mattering its position?
Ive seen people use arrays for this but that would depend on the position (I think) that you enter these strings and these positions may vary.
For example:
$myvalue = $params->get('pageclass_sfx');
$arr = explode(' ',trim($myvalue));
echo $arr[0];
$arr[0] would return: sl-articulo
$arr[1] would return: sl-categoria
Thanks.
You can use substr for that in combination with strpos:
http://nl1.php.net/substr
http://nl1.php.net/strpos
$word = 'sl-categoria';
$page_class_sfx = $params->get('page_class_sfx');
if (false !== ($pos = strpos($page_class_sfx, $word))) {
// stupid because you already have the word... But this is what you request if I understand correctly
echo 'found: ' . substr($page_class_sfx, $pos, strlen($word));
}
Not sure if you want to get a word from the string if you already know the word... You want to know if it's there? false !== strpos($page_class_sfx, $word) would be enough.
If you know exactly what strings you're looking for, then stripos() should be sufficient (or strpos() if you need case-sensitivity). For example:
$myvalue = $params->get('pageclass_sfx');
$pos = stripos($myvalue, "sl-articulo");
if ($pos === FALSE) {
// string "sl-articulo" was not found
} else {
// string "sl-articulo" was found at character position $pos
}
If you need to check if some word are in string you may use preg_match function.
if (preg_match('/some-word/', 'many some-words')) {
echo 'some-word';
}
But this solution can be used for a small list of needed words.
For other cases i suggest you to use some of this.
$myvalue = $params->get('pageclass_sfx');
$arr = explode(' ',trim($myvalue));
$result = array();
foreach($arr as $key=> $value) {
// This will calculates all data in string.
if (!isset($result[$value])) {
$result[$value] = array(); // or 0 if you don`t need to use positions
}
$result[$value][] = $key; // For all positions
// $result[$value] ++; // For count of this word in string
}
// You can just test some words like follow:
if (isset($result['sl-categoria'])) {
var_dump($result['sl-categoria']);
}

Check if string contains one of several words

I am trying to make a word filter in php, and I have come across a previous Stackoverlow post that mentions the following to check to see if a string contains certain words. What I want to do is adapt this so that it checks for various different words in one go, without having to repeat the code over and over.
$a = 'How are you ?';
if (strpos($a,'are') !== false) {
echo 'true';
}
Will it work if I mod the code to the following ?......
$a = 'How are you ?';
if (strpos($a,'are' OR $a,'you' OR $a,'How') !== false) {
echo 'true';
}
What is the correct way of adding more than one word to check for ?.
To extend your current code you could use an array of target words to search for, and use a loop:
$a = 'How are you ?';
$targets = array('How', 'are');
foreach($targets as $t)
{
if (strpos($a,$t) !== false) {
echo 'one of the targets was found';
break;
}
}
Keep in mind that the use of strpos() in this way means that partial word matches can be found. For example if the target was ample in the string here is an example then a match will be found even though by definition the word ample isn't present.
For a whole word match, there is an example in the preg_match() documentation that can be expanded by adding a loop for multiple targets:
foreach($targets as $t)
{
if (preg_match("/\b" . $t . "\b/i", $a)) {
echo "A match was found.";
} else {
echo "A match was not found.";
}
}
Read it somewhere:
if(preg_match('[word1|word2]', $a)) { }
if (strpos($ro1['title'], $search)!==false or strpos($ro1['description'], $search)!== false or strpos($udetails['user_username'], $search)!== false)
{
//excute ur code
}
If you have a fixed number of words, which is not too big you can easily make it like this:
$a = 'How are you ?';
if (strpos($a,'are') !== false || strpos($a,'you') !== false || strpos($a,'How') !== false) {
echo 'true';
}
I built methods using both str_contains and preg_match to compare speeds.
public static function containsMulti(?string $haystackStr, array $needlesArr): bool
{
if ($haystackStr && $needlesArr) {
foreach ($needlesArr as $needleStr) {
if (str_contains($haystackStr, $needleStr)) {
return true;
}
}
}
return false;
}
preg_match is always a lot slower (2-10 times slower, depending on several factors), but could be useful if you want to extend it for whole-word matching, etc.
public static function containsMulti(?string $haystackStr, array $needlesArr): bool
{
if ($haystackStr && $needlesArr) {
$needlesRegexStr = implode('|', array_map('preg_quote', $needlesArr));
return (bool) preg_match('/(' . $needlesRegexStr . ')/', $haystackStr);
}
return false;
}
If you need a multibyte-save version. try this
/**
* Determine if a given string contains a given substring.
*
* #param string $haystack
* #param string|string[] $needles
* #param bool $ignoreCase
* #return bool
*/
public static function contains($haystack, $needles, $ignoreCase = false)
{
if($ignoreCase){
$haystack= mb_strtolower($haystack);
$needles = array_map('mb_strtolower',$needles);
}
foreach ((array) $needles as $needle) {
if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
return true;
}
}
return false;
}

Filter a set of bad words out of a PHP array

I have a PHP array of about 20,000 names, I need to filter through it and remove any name that has the word job, freelance, or project in the name.
Below is what I have started so far, it will cycle through the array and add the cleaned item to build a new clean array. I need help matching the "bad" words though. Please help if you can
$data1 = array('Phillyfreelance' , 'PhillyWebJobs', 'web2project', 'cleanname');
// freelance
// job
// project
$cleanArray = array();
foreach ($data1 as $name) {
# if a term is matched, we remove it from our array
if(preg_match('~\b(freelance|job|project)\b~i',$name)){
echo 'word removed';
}else{
$cleanArray[] = $name;
}
}
Right now it matches a word so if "freelance" is a name in the array it removes that item but if it is something like ImaFreelaner then it does not, I need to remove anything that has the matching words in it at all
A regular expression is not really necessary here — it'd likely be faster to use a few stripos calls. (Performance matters on this level because the search occurs for each of the 20,000 names.)
With array_filter, which only keeps elements in the array for which the callback returns true:
$data1 = array_filter($data1, function($el) {
return stripos($el, 'job') === FALSE
&& stripos($el, 'freelance') === FALSE
&& stripos($el, 'project') === FALSE;
});
Here's a more extensible / maintainable version, where the list of bad words can be loaded from an array rather than having to be explicitly denoted in the code:
$data1 = array_filter($data1, function($el) {
$bad_words = array('job', 'freelance', 'project');
$word_okay = true;
foreach ( $bad_words as $bad_word ) {
if ( stripos($el, $bad_word) !== FALSE ) {
$word_okay = false;
break;
}
}
return $word_okay;
});
I'd be inclined to use the array_filter function and change the regex to not match on word boundaries
$data1 = array('Phillyfreelance' , 'PhillyWebJobs', 'web2project', 'cleanname');
$cleanArray = array_filter($data1, function($w) {
return !preg_match('~(freelance|project|job)~i', $w);
});
Use of the preg_match() function and some regular expressions should do the trick; this is what I came up with and it worked fine on my end:
<?php
$data1=array('JoomlaFreelance','PhillyWebJobs','web2project','cleanname');
$cleanArray=array();
$badWords='/(job|freelance|project)/i';
foreach($data1 as $name) {
if(!preg_match($badWords,$name)) {
$cleanArray[]=$name;
}
}
echo(implode($cleanArray,','));
?>
Which returned:
cleanname
Personally, I would do something like this:
$badWords = ['job', 'freelance', 'project'];
$names = ['JoomlaFreelance', 'PhillyWebJobs', 'web2project', 'cleanname'];
// Escape characters with special meaning in regular expressions.
$quotedBadWords = array_map(function($word) {
return preg_quote($word, '/');
}, $badWords);
// Create the regular expression.
$badWordsRegex = implode('|', $quotedBadWords);
// Filter out any names that match the bad words.
$cleanNames = array_filter($names, function($name) use ($badWordsRegex) {
return preg_match('/' . $badWordsRegex . '/i', $name) === FALSE;
});
This should be what you want:
if (!preg_match('/(freelance|job|project)/i', $name)) {
$cleanArray[] = $name;
}

Categories