searching for a sub string in an array in php - php

I'm trying to search for the occurrence of certain words in a string and match them with a short list in an array. I'll explain my question by means of an example.
$arrTitle = explode(" ", "Suburban Apartments");
foreach( $arrTitle as $key => $value){
echo "Name: $key, Age: $value <br />";
$words = array("hotel", "apart", "hostel");
if (in_array($value, $words)) {
echo "Exists";
}
}
I wish to compare a part of the string, in the above example 'Apartments' against the $words array for the occurrence of the string 'Apart'ments.
I hope this makes sense. Is this possible at all?
Thanks

Then you'll have to change a bit your code. Look at this below:
$arrTitle = explode(" ", "Suburban Apartments");
foreach( $arrTitle as $key => $value){
echo "Name: $key, Age: $value <br />";
$words = array("hotel", "apart", "hostel");
foreach($words as $word){
if (stripos($value, $word) !== false) {
echo "Exists";
}
}
}
Note the added foreach on the words to search and the in_array replacement for strpos.
For your personnal information, in_array checks if the $word is in the array as a whole value, which is not what you wanted. You need to check for the existence of each word using strpos or stripos (case insensitive)...

Use regular expressions to match the text.
http://php.net/manual/en/function.preg-match.php
You'll need to cycle through each of your sought array values one at a time so you'll have to loop inside your loop and run the regexp on each one looking for a match.
Make sure to make them case insensitive.

Related

Find key of first row containing a partial word match while searching a sentence

Here is my issue:
$array = array(
"1" => array("fruit", "salad", "vegetable"),
"2" => array("beef", "meat", "sausage"),
"3" => array("chocolate", "cake", "bread")
);
$sentence = "I love big sausage";
$sentence could also be I love big sausageS.
I need to associate a sentence to a category, so I need to analyze the sentence and to return the ID of the subarray matching with the sentence. For example "2" in my example.
I'm looking for the solution with the best performance. I guess I have no other choice than "explode" the sentence and "foreach" it at a minimum.
The project uses PHP7 and if it can use amazing native functions it'll be great.
I think this is best I can do.
Foreach the array and use preg_grep to find matches.
I use str_replace to replace spaces with | that is used as "or" in regex.
foreach($array as $key => $sub){
if(preg_grep("/" . str_replace(" ", "|", $sentence) . "/" ,$sub )){
echo "Match in ". $key . "\n";
}
}
https://3v4l.org/BqkW2
To match your sussageS example you can reverse the search and add .*? in the grep.
$arrSent = explode(" ", $sentence);
foreach($array as $key => $sub){
if(preg_grep("/" . implode(".*?|", $sub) . ".*?/" , $arrSent))
{
echo "Match in ". $key . "\n";
}
}
https://3v4l.org/MJqrv
But this will also accept sussage_and_beans. If you only want to match if the word is in plural (an s added at the end). Change .*? to s.
But it will be case sensitive so sussageS as in your example will not work.
but with : if(preg_grep("/" . implode("s|", $sub) . "s/i" , $arrSent))
Should make it case insensitive.
If you explode your $sentence and use a whitespace as the delimiter you will get an array of words.
You could use array_filter to remove those arrays from $array by checking if the intersect contains 1 or more words using array_intersect.
Then you could return an array using array_keys to get all the id's which contain word(s) that are in you sentence.
$array = array (
"1" => array("fruit","salad","vegetable"),
"2" => array("beef","meat","sausage"),
"3" => array("chocolate","cake","bread")
);
$expl = explode(' ', "I love big sausage");
$array = array_filter($array, function($x) use ($expl) {
return count(array_intersect($expl, $x)) > 0;
});
var_dump(array_keys($array));
Demo
That would give you:
array(1) {
[0]=>
int(2)
}
The earlier answers are making the mistake of trying to search the array of "needles" with the exploded or piped words in the "haystack". This will not work when you modify "sausage" in your sentence to "sausageS" -- there is no needle that has an s after sausage, so even if you use a case-insensitive approach it will still fail.
Because you are seeking a solitary qualifying key, it makes the most sense to stop searching as soon as a match is found. This task requirement eliminates array_filter() and preg_grep() as best performers -- they will both keep scanning data until the input is exhausted instead of stopping as soon as a match is found.
Code: (Demo)
$needlestack = [
"1" => ["fruit", "salad", "vegetable"],
"2" => ["beef", "meat", "sausage"],
"3" => ["chocolate", "cake", "bread"]
];
// $haystack = "I love big sausage";
$haystack = "I love big sausageS";
$found = null;
foreach ($needlestack as $id => $needles) {
foreach ($needles as $needle) {
if (stripos($haystack, $needle) !== false) {
$found = $id;
break 2;
}
}
}
var_export($found); // 2
stripos() will perform case-insensitively AND will allow for partial word matching (which is desirable for matching sausageS to sausage). By using nested loops and stripos(), this approach does not waste time preparing strings that will be unused.

How to find the position of multiple words in a string using strpos() function?

I want to find the position of multiple words in a string.
Forexample :
$str="Learning php is fun!";
I want to get the posion of php and fun .
And my expected output would be :-
1) The word Php was found on 9th position
2) The word fun was found on 16th position.
Here is the code that I tried, but it doesn't work for multiple words.
<?Php
$arr_words=array("fun","php");
$str="Learning php is fun!";
$x=strpos($str,$arr_words);
echo The word $words[1] was found on $x[1] position";
echo The word $words[2] was found on $x[2] position";
Does someone know what's wrong with it and how to fix it?
Any help is greatly appriciated.
Thanks!
To supplement the other answers, you can also use regular expressions:
$str="Learning php is fun!";
if (preg_match_all('/php|fun/', $str, $matches, PREG_OFFSET_CAPTURE)) {
foreach ($matches[0] as $match) {
echo "The word {$match[0]} found on {$match[1]} position\n";
}
}
See also: preg_match_all
Since you can't load an array of string words inside strpos, you could just invoke strpos twice, one for fun and one for php:
$arr_words = array("fun","php");
$str = "Learning php is fun!";
$x[1] = strpos($str,$arr_words[0]);
$x[2] = strpos($str,$arr_words[1]);
echo "The word $arr_words[0] was found on $x[1] position <br/>";
echo "The word $arr_words[1] was found on $x[2] position";
Sample Output
Or loop the word array:
$arr_words = array("fun","php");
$str = "Learning php is fun!";
foreach ($arr_words as $word) {
if(($pos = strpos($str, $word)) !== false) {
echo "The word {$word} was found on {$pos} position <br/>";
}
}
Sample Output
$str="Learning php is fun!";
$data[]= explode(" ",$str);
print_r($data);//that will show you index
foreach($data as $key => $value){
if($value==="fun") echo $key;
if($value==="php") echo $key;
}
Key is the exact position but index start with 0 so keep in mind to modify your code accordingly, may be echo $key+1 (a number of ways, depends on you).
You were doing it in a wrong way check the function
strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
haystack
The string to search in.
needle
If needle is not a string, it is converted to an integer and applied as the ordinal value of a character.
offset
If specified, search will start this number of characters counted from the beginning of the string.
Refer Docs
Here within your example
$arr_words=array("fun","php");
$str="Learning php is fun!";
$x=strpos($str,$arr_words);
$arr_words is an array not a string or not an integer
so you need to loop it or need to manually pass the key as
$x[1] = strpos($str,$arr_words[0]);
$x[2] = strpos($str,$arr_words[1]);
or
foreach($arr_words as $key => $value){
$position = strpos($str,$value);
echo "The word {$value} was found on {$position}th position"
}
Just another answer:
<?php
$arr_words=array("fun","php");
$str="Learning php is fun!";
foreach($arr_words as $needle) {
$x = strpos($str, $needle);
if($x)
echo "The word '$needle' was found on {$x}th position.<br />";
}
?>
You can not use function strpos if the second params is an array.
This is easiest way:
<?php
$words = array("php","fun");
$str = "Learning php is fun!";
foreach ($words as $word) {
$pos = strpos($str, $word);
// Found this word in that string
if($pos) {
// Show you message here
}
}

Search a letter in a list of words?

I have an array called 'words' storing many words.
For example:
I have 'systematic', 'سلام','gear','synthesis','mysterious', etc.
NB: we have utf8 words too.
How to query efficiently to see which words include letters 's','m','e' (all of them) ?
The output would be:
systematic,mysterious
I have no idea how to do such a thing in PHP. It should be efficient because our server would suffer otherwise.e.
Use a regular expression to split each string into an array of characters, and use array_intersect() to find out if all the characters in your search array is present in the split array:
header('Content-Type: text/plain; charset=utf8');
$words = array('systematic', 'سلام','gear','synthesis','mysterious');
$search = array('s','m','e');
foreach ($words as $word) {
$char_array = utf8_str_split($word);
$contains = array_intersect($search, $char_array) == $search;
echo sprintf('%s : %s', $word, (($contains) ? 'True' : 'False'). PHP_EOL);
}
function utf8_str_split($str) {
return preg_split('/(?!^)(?=.)/u', $str);
}
Output:
systematic : True
سلام : False
gear : False
synthesis : False
mysterious : True
Demo.
UPDATE: Or, alternatively, you could use array_filter() with preg_match():
$array = array_filter($words, function($item) {
return preg_match('~(?=[^s]*s)(?=[^m]*m)(?=[^e]*e)~u', $item);
});
Output:
Array
(
[0] => systematic
[4] => mysterious
)
Demo.
This worked to me:
$words = array('systematic', 'سلام','gear','synthesis','mysterious');
$letters=array('s','m', 'e');
foreach ($words as $w) {
//print "lets check word $w<br>";
$n=0;
foreach ($letters as $l) {
if (strpos($w, $l)!==false) $n++;
}
if ($n>=3) print "$w<br>";
}
It returns
systematic
mysterious
Explanation
It uses nested foreach: one for the words and the other one for the letters to be matched.
In case any letter is matched, the counter is incremented.
Once the letters loop is over, it checks how many matches were there and prints the word in case it is 3.
Something like this:
$words = array('systematic', 'سلام','gear','synthesis','mysterious');
$result=array();
foreach($words as $word){
if(strpos($word, 's') !== false &&
strpos($word, 'm') !== false &&
strpos($word, 'e') !== false){
$result[] = $word;
}
}
echo implode(',',$result); // will output 'systematic,mysterious'
Your question is wide a little bit.
What I understand from your question that's those words are saved in a database table, so you may filter the words before getting them into the array, using SQL like function.
in case you want to search for a letters in an array of words, you could loop over the array using foreach and each array value should be passed to strpos function.
http://www.php.net/function.strpos
why not use PREG_GREP
$your_array = preg_grep("/[sme]/", $array);
print_r($your_array);
WORKING DEMO

regular expression word preceded by char

I want to grab a specific string only if a certain word is followed by a = sign.
Also, I want to get all the info after that = sign until a / is reached or the string ends.
Let's take into example:
somestring.bla/test=123/ohboy/item/item=capture
I want to get item=capture but not item alone.
I was thinking about using lookaheads but I'm not sure it this is the way to go. I appreciate any help as I'm trying to grasp more and more about regular expressions.
[^/=]*=[^/]*
will give you all the pairs that match your requirements.
So from your example it should return:
test=123
item=capture
Refiddle Demo
If you want to capture item=capture, it is straightforward:
/item=[^\/]*/
If you want to also extract the value,
/item=([^\/]*)/
If you only want to match the value, then you need to use a look-behind.
/(?<=item=)[^\/]*/
EDIT: too many errors due to insomnia. Also, screw PHP and its failure to disregard separators in a character group as separators.
Here is a function I wrote some time ago. I modified it a little, and added the $keys argument so that you can specify valid keys:
function getKeyValue($string, Array $keys = null) {
$keys = (empty($keys) ? '[\w\d]+' : implode('|', $keys));
$pattern = "/(?<=\/|$)(?P<key>{$keys})\s*=\s*(?P<value>.+?)(?=\/|$)/";
preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);
foreach ($matches as & $match) {
foreach ($match as $key => $value) {
if (is_int($key)) {
unset($match[$key]);
}
}
}
return $matches ?: FALSE;
}
Just trow in the string and valid keys:
$string = 'somestring.bla/test=123/ohboy/item/item=capture';
$keys = array('test', 'item');
$keyValuePairs = getKeyValue($string, $keys);
var_dump($keyValuePairs);

searching for sub strings from multiple category arrays in PHP

I have a piece of text, which is around 1500 words long. I have to search for occurrences of certain words in this text and group them by categories. For example, if any of the following words are found: "dalmation", "boxer", "terrier" are found, then echo "Canines", if "lion", "leopard", "cheeta" are found then echo "Felines" and so on and so forth. Words found within other words are also acceptable, for example, "foxterrier".
I currently am using the following to go through the string:
$arrTitle = explode(" ", "Loren ipsum dolor ...............");
// For dogs:
foreach( $arrTitle as $key => $value){
echo "Name: $key, Value: $value <br />";
$words = array("dalmation", "boxer", "terrier");
foreach($words as $word){
if (stripos($value, $word) !== false) {
echo "Canines Exists";
}
}
}
//For cats:
foreach( $arrTitle as $key => $value){
echo "Name: $key, Value: $value <br />";
$words = array("lion", "leopard", "cheeta");
foreach($words as $word){
if (stripos($value, $word) !== false) {
echo "Felines Exists";
}
}
}
// ...Repeat the above for all categories.
The processing takes ages and also I'm not sure it's the most efficient way of doing things. Please can anyone help me find a speedier way of doing this? your help will be most appreciated.
You're in my area here!
By far the fastest way is to array_flip and then use isset to check if the word exists, took me a long time to figure that one out. This will remain virtually instant for literally millions of words (searching in a string or array will never match this in speed), but it can eat up the RAM is such cases.
You should strtolower your $words first.
$arrTitle = strtolower($arrTitle);
$arrTitle = explode(' ', $arrTitle);
$words=array('dalmation', 'boxer', 'terrier');
$words=array_flip($words);
foreach($arrTitle as $key => $value)
{
echo "Name: $key, Value: $value <br />";
if (isset($words[$value])) echo $value.' Exists <br/>';
}
You could compose regexps of similar words, then do a single search for each. Regexps aren't incredibly fast, but they're faster than running your own loops in PHP. :-)
$groups = array(
'Canines' => array("dalmation", "boxer", "terrier"),
'Felines' => array("lion", "leopard", "cheeta")
);
foreach ($groups as $group => $members) {
$pattern = "/" . implode("|", $members) . "/i";
if (preg_match($pattern, $src)) {
print $group;
}
}
Meta code. I haven't tested this.
The idea here is to remove the actual groups from your code. After all, your data could be loaded from a database or some other source; the data structure and data should be separate.
By using the arrays as above, you can add new groups without changing the meat of the comparison code. I.e. "Fish" become a group, not a chunk of code.
As an optimization for your current script you should be checking for all words in the same loop instead of running a foreach on $arrTitle multiple times. Or as an alternative just use stripos on the entire document for each word.
If this is for an actual production site and needs to be run repeatedly I wouldn't be doing this in PHP at all. A database (MySQL or Solr) with a proper index on your documents would produce much faster results.

Categories