0

i have two arrays and then tried to get value array from matching both. it's impossible? let's check this out my code

$text = array(                                                               
              "I had locked the door before I left my home",                 
              "I was late. The train had left",                            
              "She had already found the key, before I broke the door",  
              "n..."                                                         
         );

$inline =  array("locked","found");

$output = ?                        
print_r($output);                                 

// i want a $output like this                                                       
// array(                                                                  
//      [0] => "I had locked the door before I left my home"               
//      [2] => "She had already found the key, before I broke the door"     
//    ); 

how can i do this? thanks :)

11
  • looked? or locked? Commented Dec 20, 2017 at 4:46
  • opss .. typo sir, i mean locked :) Commented Dec 20, 2017 at 4:51
  • Do you also want a string like The birds flocked together. too? Or do you want to match only whole words? This is a critical decision when selecting the best method for your project. Commented Dec 20, 2017 at 7:32
  • Yes of course, like the birds flocked together.. hmm, what the best answer in here you look? Because almost everything has the same result. Commented Dec 20, 2017 at 8:05
  • I am isolating the issue of overmatching. You see if your search string exists as a substring of a larger word, you may be retaining results that you don't want. Will you want to match in a case-sensitive way? These decisions determine the right fit for your task. The clearer your question, the better your answers can be. Commented Dec 20, 2017 at 8:32

5 Answers 5

2

You can use array_filter() function

$output = array_filter($text, function($e) use($inline){
    foreach ($inline as $search) {
        if (strpos($e, $search) > -1) return true;
    }
    return false;
});

print_r($output);
Sign up to request clarification or add additional context in comments.

Comments

1

I have done with one foreach and i have used preg_quote and preg_grep for this :-

$finaloutput = array();
$text = array(                                                               
          "I had locked the door before I left my home",                 
          "I was late. The train had left",                            
          "She had already found the key, before I broke the door",  
          "n..."                                                         
     );
$inline =  array("locked","found");
foreach($inline as $find){
    $input = preg_quote($find, '~');
    $result = preg_grep('~' . $input . '~', $text); 
    $finaloutput[] = $result;
}
$finalArray = call_user_func_array('array_merge', $finaloutput);
echo "<pre>"; print_r($finalArray);

Even you serached with Locked or Loc or lo it will fetch your data. Hope it helps!

6 Comments

This is NOT the best use of preg_grep() please read my answer.
@mickmackusa Thanks can you elaborate what i have done wrong :)
You are under-utilizing the awesome power of preg_grep(). By combining the $inline values into a single pattern, you can iterate the $text elements in one hit. Your method is doing two sweeps (locked then found) on the $text array. Then you have to go to the trouble to merge your results. If you have more questions about my answer, please leave me a comment there.
Ok thanks you have mean i don't need foreach loop beacuse execution run twice for text array we can do directly with preg_grep??
@mickmackusa i think you are right i will follow these instructions next time :)
|
1

You can use strpos and have nested foreach

$text = array(                                                               
              "I had locked the door before I left my home",                 
              "I was late. The train had left",                            
              "She had already found the key, before I broke the door",  
              "n..."                                                         
         );

$inline =  array("locked","found");
$output = array();
//Loop our sentences
foreach($text as $key => $sentence){
    //Check the word
    foreach($inline as $find){
        //Check if the word is in sentence
        if(strpos($sentence,$find) !== false){
            $output[$key] = $sentence;
        }
    }
}
print_r($output);

RESULT

Array
(
    [0] => I had locked the door before I left my home
    [2] => She had already found the key, before I broke the door
)

7 Comments

The condition for strpos will fail if $inline has the the first word of $text element. e.g. $inline = array("I"); would return only the first and third $text element. Second will not be included
@Emerald I should add !== false instead in condition. Thanks for pointing that.
It may be inconsequential, but you are disassociating the keys by generating a new indexed result array. ... just saying.
@mickmackusa What do you mean? Can you please explain it more? Thanks
I'm only saying that the OP asked for keys [0] and [2] in the result, but yours generates [0] and [1]. This probably amounts to nothing. Just a point of difference between generating a new output array, and filtering the input array.
|
0

Not an expert, but I like to use preg_match myself. Not sure if there is a performance hit for using it instead of strpos. But being able to use the OR operator between patterns makes it easy to just implode the patterns into a string and search all the patterns at once instead of having to make another loop.

$texts = [
    "I had locked the door before I left my home",
    "I was late. The train had left",
    "She had already found the key, before I broke the door",
    "n..."
];
$patterns = [ "locked", "found" ];
$output = [];

foreach( $texts as $text )
{
    if( preg_match( '#' . implode( '|', $patterns ) . '#', $text )) {
        $output[] = $text;
    }
}

print_r( $output );

Here is a modification as per @mickmackusa suggestion which would be needed in situations where you do not want any of the characters in the patterns to be misinterpreted as regex control characters (ex: a period acting as a wildcard ) and if you want to ensure that the pattern words you are looking for are single words (not part of another word).

foreach( $texts as $key => $text )
{
    if( preg_match( '#\b\Q' . implode( '\E\b|\b\Q', $patterns ) . '\E\b#', $text )) {
        $output[$key] = $text;
    }
}

3 Comments

Unfortunately, your method will match and retain the following element: The birds flocked together. See my answer.
True, but the question never specified that they wanted only whole words, and that they wanted to match values within the strings given. It's possible that the boundaries would leave out results that Luckyman wants.
Technically true.
0

preg_grep() is perfectly suited to filter your array elements with one function call. The only preparation needed is to add word boundaries and make the strings literal with (\Q..\E).

In truth, your sample $inline data doesn't require \Q and \E, but this is just as a precaution. In the same vein, \b are not required for your sample input data but this is best practice for future-proofing your script.

Code: (Demo)

$text = array(                                                               
    "I had locked the door before I left my home",                 
    "I was late. The train had left",                            
    "She had already found the key, before I broke the door",  
    "n..."                                                         
);

$inline =  array("locked","found");
$pattern='/\b\Q'.implode('\E\b|\b\Q',$inline).'\E\b/';  // renders as: /\b\Qlocked\E\b|\b\Qfound\E\b/
var_export(preg_grep($pattern,$text));

Output:

array (
  0 => 'I had locked the door before I left my home',
  2 => 'She had already found the key, before I broke the door',
)

For more reading on \Q and \E see the Special Characters section of: https://www.regular-expressions.info/characters.html

For more reading on \b see: https://www.regular-expressions.info/wordboundaries.html

For more reading on | (Alternation) see: https://www.regular-expressions.info/alternation.html

p.s. if you need case-insensitive matching use the i pattern modifier:

$pattern='/\b\Q'.implode('\E\b|\b\Q',$inline).'\E\b/i';

2 Comments

i don't understand this :- $pattern='/\b\Q'.implode('\E\b|\b\Q',$inline).'\E\b/'; but iknow how impode works but your pattern '/\b\Q'' ? can you clear
All characters between \Q and \E will be treated literally by the regex engine. This is "function-less" alternative to preg_quote()'s effect. Word boundaries prevent matching larger words like flocked.

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.