Jump to content

How to find 2 or more words in a string with preg_match?


noidea
Go to solution Solved by .josh,

Recommended Posts

hay there  cheesy.gif

How can i check for say 2 or more words in a string...

Now I know this checks for 2 words on a "OR" basis

if(preg_match("/$findthis|$this/i", $text_to_search))
{

//do something

}

So this ill check to see if the 

$text_to_search

contains either

$findthis

  or

$this

but i need it to check with the "and" operator - so for example..


search

$text_to_search

for 

$findthis

and

$this

how can i do this?

many thanks smiley.gif

 

Link to comment
Share on other sites

You could do something like preg_match("/$findthis/i",$text_to_search) && preg_match("/$this/i",$text_to_search) ? /* code here will be executed if $text_to_search includes both $findthis and $this */ : /* code here will be executed if either only $findthis, only $this or none of both was found in $text_to_search */;

 

Of course, you can refine the conditions to work with the boolean OR operator (||) or something like that.

Link to comment
Share on other sites

You could do something like preg_match("/$findthis/i",$text_to_search) && preg_match("/$this/i",$text_to_search) ? /* code here will be executed if $text_to_search includes both $findthis and $this */ : /* code here will be executed if either only $findthis, only $this or none of both was found in $text_to_search */;

 

Of course, you can refine the conditions to work with the boolean OR operator (||) or something like that.

 

hi thanks for the reply

 

This wont work for my needs as the amount of words enterd will vary... imagine a search scenario where the user can enter multiple words

Link to comment
Share on other sites

 

put the search strings into an array and loop through them. 

$searchTerms = array('foo','bar');
$allMatched = true;
foreach ($searchTerms as $searchTerm) {
  if ( preg_match('~'.$searchTerm.'~',$text_to_search) == false )  {
    $allMatched = false;
    break;
  }
}

 

Hi thanks for helpig but i really dont understand your code...

I have tried putting the users entered search words in an array which works but for me this basically does the same as the "or"

it outputs results $text_to_search if 'foo' or 'bar' are found where i only want it to out put if both words exists

 

Also what do the '~' operators mean?

 

im sure its my fault its not working as im trying to get it to work within my script ... im basically having to loop through files while this is goin on

 

example:

function SplitQuery($this_query)                              //Function to return each search word pipe operator for "or" for preg_match
{
$all_words = explode(" ", $this_query);
foreach($all_words as $val => $word)
{
$return = $return . $word."|";
}
$to_return = trim($return, "|");
return $to_return;                                                      // Will return "each|keyword|seperated"
}


$query = $_POST['q'];                                                 //Users posted search words

$search_str = SplitQuery($query);                            //Get each search word from phrase

$news_path = "news";                                               // Folder where files are stored

$dir = opendir($news_path);                                      //Open news Folder

while (false !== ($file = readdir($dir)))
{
if ($file != "." && $file != "..")
{
$release_file = trim($file);

$file_path = $news_path."/".$file;

if(!is_dir($file_path))                                                     //Make sure file is not a sub dir
{
$file_contents = file_get_contents($file_path);            //Get the contents of each file
$explode_parts = explode("|",$file_contents);             //Put contents in array 

$news_headline = $explode_parts[1]);                       //News Headline
$news_content = $explode_parts[2]);                        //News Main Content

if(preg_match("/$search_str/i", $news_headline." ".$news_content))            //Search to see if user 
{
$search_data[] = $news_headline."|".$news_content."|";
}

}
}
}
closedir($dir);                                                            //Close Dir 

the above works but only on an OR basis where i need to check to see if ALL entered words are in section of text

 

Sorry im not very good at explaining myself well  lloll

Link to comment
Share on other sites

preg functions accept a string as argument containing your regular expression, delimited by two of the same characters, like, as commonly used (since you need to escape the starting character if you want to match them directly in your regular expression) are "#", "~" or "/".

 

What .josh's code did was to create an array with the search terms in it ("foo" and "bar" have a long tradition of being used as examples in the IT branch), then he loops through that same array, creates a regular expression out of them and matches them against the text to search through, and if those functions return false, the whole variable $allMatched becomes false and you know that the text did not include all the keywords the user searched for.

Link to comment
Share on other sites

preg functions accept a string as argument containing your regular expression, delimited by two of the same characters, like, as commonly used (since you need to escape the starting character if you want to match them directly in your regular expression) are "#", "~" or "/".

 

What .josh's code did was to create an array with the search terms in it ("foo" and "bar" have a long tradition of being used as examples in the IT branch), then he loops through that same array, creates a regular expression out of them and matches them against the text to search through, and if those functions return false, the whole variable $allMatched becomes false and you know that the text did not include all the keywords the user searched for.

 

yeah i get the foo and bar thing lol

 

I just dont understand how the code helps my scinario (posted above) or how to inplemtent it.. i have tried but i dont get the results i need

 

Im still getting the results based on "or" so if "foo" or "bar" then results where found but i dont need that

I need AND so if "foo" and "bar" exists then boom! job done!

 

I cant believe i cant even find a simple solution for this

Link to comment
Share on other sites

from my understanding, as im using a while loop i need to create a function based on the code that josh posted

 

and thats my problem lol - i dont understand the logic behind it as it was not explained - im grateful for the help but its only useful if it explains how it helps

 

I get i need to break each word up the user entered but then i dont know what do to next to check that ALL the words (needles) exist in a given haystack

Link to comment
Share on other sites

ok i think using joshs code i figured it out

function SplitQuery($this_query, $to_search)
{
$searchTerms = explode(" ", $this_query);
$allMatched = 1;

foreach ($searchTerms as $searchTerm)
{
if ( preg_match('/'.$searchTerm.'/i',$to_search) == false )
{
$allMatched = 0;
}
}
return $allMatched;
}

so while looping through my files i just need to do

if(SplitQuery($this_query, $to_search) == 1) 
{
$data_to_display[] = $news_headline."|".$news_content;      //This will collect only data that contains words typed in $this_query
}

cheers for helpin, i just cant believe something so simple has to be so complex lol

Link to comment
Share on other sites

@irate:  The issue with your solution is that you had two preg_matches in the condition.  But the point he made about that was that there are a variable amount of keywords to preg_match.  It might be just 1, or it might be 10.  Look at his code; it explodes a string at the spaces.  So, the only way to make your solution scalable is to build the condition as a string and then eval it, which isn't a good thing to do.   That is why I showed how to keep the condition as a single preg_match by looping through the keywords. 

Link to comment
Share on other sites

You may also want to use word boundaries (\b) to do an exact word match only, given the following string:

 

My name is Andy.

 

Matching /and/i would return true whereas matching /\band\b/i would return false. See http://www.regular-expressions.info/wordboundaries.html

 

I don't know if you use OOP but you would probably be best grouping things like this into a static class, so to start you off:

 

class Regex {  public static function test($expressions, $term) {    if ( !is_array($expressions) ) {      $expressions = array($expressions);    }    return count(array_filter($expressions, function($expression) use ($term) {      return preg_match($expression, $term);    }));  }} var_dump(Regex::test(array('~and~i'), 'My name is Andy')); // => int 1var_dump(Regex::test(array('~\band\b~i'), 'My name is Andy')); // => int 0var_dump(Regex::test(array('~\bname\b~i', '~\bandy\b~i'), 'My name is Andy')); // => int 2

 
This uses array_filter to iteratively match the regular expressions against the given string, returning false to the array_filter callback removes the elements from the array, so by returing a count of the remaining arrays elements, we can use the returned integer as a boolean value.
Link to comment
Share on other sites

@.josh: Hm, true that, but doesn't your code invoke preg_match at least twice, too? ;)

Anyway, yeah, point taken. I'm still learning the extensive parts of PHP, as in, query minimization, storage release and so on.

Link to comment
Share on other sites

@.josh: Hm, true that, but doesn't your code invoke preg_match at least twice, too? ;)

Anyway, yeah, point taken. I'm still learning the extensive parts of PHP, as in, query minimization, storage release and so on.

 

Yeah but his code allowed a variable number of matches to be made, if the array passed contained say 7 patterns, it would call preg_match dynamically 7 times.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.