Decoding anagram with recursive function doesn't give expected output - php

So I'm trying to decode an anagram into words from my dictionary file. But my recursive function isn't behaving like I'm expecting.
The thoughts about the code is to eliminate letters as they are used on words and output me the string it came up with.
<?php
function anagram($string, $wordlist)
{
if(empty($string))
return;
foreach($wordlist as $line)
{
$line = $org = trim($line);
$line = str_split($line);
sort($line);
foreach($line as $key => $value)
{
if($value != $string[$key])
{
continue 2;
}
}
echo $org . anagram(array_slice($string, count($line)), $wordlist);
}
echo PHP_EOL;
}
$string = "iamaweakishspeller";
$string = str_split($string);
sort($string);
$file = file('wordlist');
anagram($string, $file);
This is my result for now, it looks awful, but I'm having some issues with the code - it's going into an indefinite loop with the same roughly 200 words from the word list.
Can someone take an extra peak at this?

Situation
You have a dictionary(file) and an anagram which contains one or multiple words. The anagram doesn't contain any punctuation or letter case of the original word(s).
Now you want to find all true solutions where you use up all characters of the anagram and decode it into word(s) from the dictionary.
Note: There is a chance that you find multiple solutions and you will never know which one the original text was and in which order the words were, since the characters of multiple words are mixed in the anagram and you don't have punctuation or the case of the letters in it.
Your code
The problem in your current code is exactly that you have multiple words mixed together. If you sort them now and you want to search them in the dictionary you won't be able to find them, since the characters of multiple words are mixed. Example:
anagram = "oatdgc" //"cat" + "dog"
wordList = ["cat", "dog"]
wordListSorted = ["act", "dgo"]
anagramSorted = acdgot
↓↓↓
WordListSorted[0] → cat ✗ no match
WordListSorted[1] → dog ✗ no match
Solution
First I will explain in theory how we construct all possible true solutions and then I explain how every part in the code works.
Theory
So to start we have an anagram and a dictionary. Now we first filter the dictionary by the anagram and only keep the words, which can be constructed by the anagram.
Then we go through all words and for each word we add it to a possible solution, remove it from the anagram, filter the dictionary by the new anagram and call the function with the new values recursively.
We do this until either the anagram is empty and we found a true solution, which we add to our solution collection, or there are no words remaining and it is not a possible solution.
Code
We have two helper functions array_diff_once() and preSelectWords() in our code.
array_diff_once() is pretty much the same as the built-in array_diff() function, except that it only removes values once and not all occurrences. Otherwise there isn't much to explain. It simply loops through the second array and removes the values once in the first array, which then gets returned.
function array_diff_once($arrayOne, $arrayTwo){
foreach($arrayTwo as $v) {
if(($key = array_search($v, $arrayOne)) !== FALSE)
array_splice($arrayOne, $key, 1);
}
return $arrayOne;
}
preSelectWords() takes an anagram and a word list as argument. It simply checks with the help of array_diff_once(), which words of the word list can be constructed with the given anagram. Then it returns all possible words from the word list, which can be constructed with the anagram.
function preSelectWords($anagram, $wordList){
$tmp = [];
foreach($wordList as $word){
if(!array_diff_once(str_split(strtolower($word)), $anagram))
$tmp[] = $word;
}
return $tmp;
}
Now to the main function decodeAnagram(). We pass the anagram and a word list, which we first filter with preSelectWords(), as arguments to the function.
In the function itself we basically just loop through the words and for each word we remove it from the anagram, filter the word list by the new anagram and add the word to a possible solution and call the function recursively.
We do this until either the anagram is empty and we found a true solution, which we add to our solution array, or there are no words left in the list and with that no possible solution.
function decodeAnagram($anagram, $wordList, $solution, &$solutions = []){
if(empty($anagram) && sort($solution) && !isset($solutions[$key = implode($solution)])){
$solutions[$key] = $solution;
return;
}
foreach($wordList as $word)
decodeAnagram(array_diff_once($anagram, str_split(strtolower($word))), preSelectWords(array_diff_once($anagram, str_split(strtolower($word))), $wordList), array_merge($solution, [$word]), $solutions);
}
Code
<?php
function decodeAnagram($anagram, $wordList, $solution, &$solutions = []){
if(empty($anagram) && sort($solution) && !isset($solutions[$key = implode($solution)])){
$solutions[$key] = $solution;
return;
}
foreach($wordList as $word)
decodeAnagram(array_diff_once($anagram, str_split(strtolower($word))), preSelectWords(array_diff_once($anagram, str_split(strtolower($word))), $wordList), array_merge($solution, [$word]), $solutions);
}
function preSelectWords($anagram, $wordList){
$tmp = [];
foreach($wordList as $word){
if(!array_diff_once(str_split(strtolower($word)), $anagram))
$tmp[] = $word;
}
return $tmp;
}
function array_diff_once($arrayOne, $arrayTwo){
foreach($arrayTwo as $v) {
if(($key = array_search($v, $arrayOne)) !== FALSE)
array_splice($arrayOne, $key, 1);
}
return $arrayOne;
}
$solutions = [];
$anagram = "aaaeeehiikllmprssw";
$wordList = ["I", "am", "a", "weakish", "speller", "William", "Shakespeare", "other", "words", "as", "well"];
//↑ file("wordlist", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
decodeAnagram(str_split(strtolower($anagram)), preSelectWords(str_split(strtolower($anagram)), $wordList), [], $solutions);
print_r($solutions);
?>
Output
Array
(
[Iaamspellerweakish] => Array
(
[0] => I
[1] => a
[2] => am
[3] => speller
[4] => weakish
)
[ShakespeareWilliam] => Array
(
[0] => Shakespeare
[1] => William
)
)
(Ignore the keys here, since those are the identifiers of the solutions)

Related

How to remove, just once, a word that appears several times in the array

I've researched all sorts of ways, but I haven't found a solution for this case.
Basically I have to see if the word repeats and just remove the first occurrence of it in the array. For example:
$array_words = ['harmony', 'Acrobat', 'harmony', 'harmony'];
How do I check the repeated word, just once, leaving the array like this:
$array_final = ['Acrobat', 'harmony', 'harmony'];
I threw together this simple loop, and explained it with comments
$array_words = ['harmony', 'Acrobat', 'harmony', 'harmony'];
//get a count of each word in the array
$counted_values = array_count_values($array_words);
//hold the words we have already checked
$checked_words = [];
//variable to hold our output after filtering
$output = [];
//loop over words in array
foreach($array_words as $word) {
//if word has not been checked, and appears more than once
if(!in_array($word, $checked_words) && $counted_values[$word] > 1) {
//add word to checked list, continue to next word in array
$checked_words[] = $word;
continue;
}
//add word to output
$output[] = $word;
}
$output value
Array
(
[0] => Acrobat
[1] => harmony
[2] => harmony
)
GrumpyCrouton's solution is probably neater, but here's another way. Basically you put all the values into a single string, and then use string functions to do the work.
Code is commented with explanatory notes:
<?php
$array_words = ['harmony', 'Acrobat', 'harmony', 'harmony'];
$array_words_unique = array_unique($array_words); //get a list of unique words from the original array
$array_str = implode(",", $array_words);
foreach ($array_words_unique as $word) {
//count how many times the word occurs
$count = substr_count($array_str, $word);
//if it occurs more than once, remove the first occurence
if ($count > 1) {
//find the first position of the word in the string, then replace that with nothing
$pos = strpos($array_str, $word);
$array_str = substr_replace($array_str, "", $pos, strlen($word));
}
}
//convert back to an array, and filter any blank entries caused by commas with nothing between them
$array_final = array_filter(explode(",", $array_str));
var_dump($array_final);
Demo: https://3v4l.org/i1WKI
Credit to Using str_replace so that it only acts on the first match? for code to replace only the first occurence of a string inside another string.
We can use an array to keep track of each item that has been removed, and then use array_shift to move out of the item and count to limit loop overruns
<?php
$record = ['harmony','harmony', 'Acrobat', 'harmony', 'harmony','last'];
for($i=0,$count=count($record),$stack=array();$i<$count;$i++){
$item = array_shift($record);
in_array($item,$record) && !in_array($item,$stack)
? array_push($stack,$item)
: array_push($record,$item);
}
var_dump($record);

Filter an array of words by an array of single letters it should ONLY contain

I currently have two PHP arrays:
array('a','c','r','r')
array('carr','car','arc','ra','c','abc','do','aa','rr')
My desired result is:
array('carr','car','arc','ra','c','rr')
i.e. filtering out 'abc','do','aa' because I wish to filter out words that:
don't contain a, c or r
contain more/multiple a,c,r than I have in array 1.
I have tried array_filter() but I don't seem to be able to make it work.
One way to do this:
Count how many times each letter occurs in your first array, using array_count_values.
Then in your array_filter callback function, split each word into individual letters, and also count how many times each of them occurs. Then loop over those counted letters. If the current letter does not occur in your letter-count-array, or its count is greater than that in your letter-count-array, return false.
$letters = ['a','c','r','r'];
$words = ['carr','car','arc','ra','c','abc','do','aa','rr'];
$letterCounts = array_count_values($letters);
$filtered = array_filter($words, function($word) use ($letterCounts) {
$wordLetterCounts = array_count_values(mb_str_split($word));
foreach($wordLetterCounts as $wordLetter => $count) {
if(!isset($letterCounts[$wordLetter]) || $letterCounts[$wordLetter] < $count) {
return false;
}
}
return true;
});
var_dump($filtered);
As you iterate the array of words, you can iterate the array of letters and make single-letter replacements. If all letters in the word are consumed, the word is saved.
A regular expression isn't actually necessary because the letter is literal, but preg_replace() offers a limiting parameter and str_replace() doesn't.
Code: (Demo)
$needles = ['a','c','r','r'];
$haystacks = ['carr','car','arc','ra','c','abc','do','aa','rr', 'rrr'];
$result = [];
foreach ($haystacks as $i => $haystack) {
foreach ($needles as $needle) {
$haystack = preg_replace("/$needle/", '', $haystack, 1);
}
if (!$haystack) {
$result[] = $haystacks[$i];
}
}
var_export($result);
The above can actually be boiled down to this: (Demo)
$regexes = array_map(fn($v) => "/$v/", $needles);
var_export(
array_filter(
$haystacks,
fn($hay) => !preg_replace($regexes, '', $hay, 1)
)
);

How to check array data that matches from random characters in php?

I have an array like below:
$fruits = array("apple","orange","papaya","grape")
I have a variable like below:
$content = "apple";
I need to filter some condition like: if this variable matches at least one of the array elements, do something. The variable, $content, is a bunch of random characters that is actually one of these available in the array data like below:
$content = "eaplp"; // it's a dynamically random char from the actual word "apple`
what have I done was like the below:
$countcontent = count($content);
for($a=0;$a==count($fruits);$a++){
$countarr = count($fruits[$a]);
if($content == $fruits[$a] && $countcontent == $countarr){
echo "we got".$fruits[$a];
}
}
I tried to count how many letters these phrases had and do like if...else... when the total word in string matches with the total word on one of array data, but is there something that we could do other than that?
We can check if an array contains some value with in_array. So you can check if your $fruits array contains the string "apple" with,
in_array("apple", $fruits)
which returns a boolean.
If the order of the letters is random, we can sort the string alphabetically with this function:
function sorted($s) {
$a = str_split($s);
sort($a);
return implode($a);
}
Then map this function to your array and check if it contains the sorted string.
$fruits = array("apple","orange","papaya","grape");
$content = "eaplp";
$inarr = in_array(sorted($content), array_map("sorted", $fruits));
var_dump($inarr);
//bool(true)
Another option is array_search. The benefit from using array_search is that it returns the position of the item (if it's found in the array, else false).
$pos = array_search(sorted($content), array_map("sorted", $fruits));
echo ($pos !== false) ? "$fruits[$pos] found." : "not found.";
//apple found.
This will also work but in a slightly different manner.
I split the strings to arrays and sort them to match eachoter.
Then I use array_slice to only match the number of characters in $content, if they match it's a match.
This means this will match in a "loose" way to with "apple juice" or "apple curd".
Not sure this is wanted but figured it could be useful for someone.
$fruits = array("apple","orange","papaya","grape","apple juice", "applecurd");
$content = "eaplp";
$content = str_split($content);
$count = count($content);
Foreach($fruits as $fruit){
$arr_fruit = str_split($fruit);
// sort $content to match order of $arr_fruit
$SortCont = array_merge(array_intersect($arr_fruit, $content), array_diff($content, $arr_fruit));
// if the first n characters match call it a match
If(array_slice($SortCont, 0, $count) == array_slice($arr_fruit, 0, $count)){
Echo "match: " . $fruit ."\n";
}
}
output:
match: apple
match: apple juice
match: applecurd
https://3v4l.org/hHvp3
It is also comparable in speed with t.m.adams answer. Sometimes faster sometimes slower, but note how this code can find multiple answers. https://3v4l.org/IbuuD
I think this is the simplest way to answer that question. some of the algorithm above seems to be "overkill".
$fruits = array("apple","orange","papaya","grape");
$content = "eaplp";
foreach ($fruits as $key => $fruit) {
$fruit_array = str_split($fruit); // split the string into array
$content_array = str_split($content); // split the content into array
// check if there's no difference between the 2 new array
if ( sizeof(array_diff($content_array, $fruit_array)) === 0 ) {
echo "we found the fruit at key: " . $key;
return;
}
}
What about using only native PHP functions.
$index = array_search(count_chars($content), array_map('count_chars', $fruits));
If $index is not null you will get the position of $content inside $fruits.
P.S. Be aware that count_chars might not be the fastest approach to that problem.
With a random token to search for a value in your array, you have a problem with false positives. That can give misleading results depending on the use case.
On search cases, for example wrong typed words, I would implement a filter solution which produces a matching array. One could sort the results by calculating the levenshtein distance to fetch the most likely result, if necessary.
String length solution
Very easy to implement.
False positives: Nearly every string with the same length like apple and grape would match.
Example:
$matching = array_filter($fruits, function ($fruit) use ($content) {
return strlen($content) == strlen($fruit);
});
if (count($matching)) {
// do your stuff...
}
Regular expression solution
It compares string length and in a limited way containing characters. It is moderate to implement and has a good performance on big data cases.
False positives: A content like abc would match bac but also bbb.
Example:
$matching = preg_grep(
'#['.preg_quote($content).']{'.strlen($content).'}#',
$fruits
);
if (count($matching)) {
// do your stuff...
}
Alphanumeric sorting solution
Most accurate but also a slow approach concerning performance using PHP.
False positives: A content like abc would match on bac or cab.
Example:
$normalizer = function ($value) {
$tokens = str_split($value);
sort($tokens);
return implode($tokens);
};
$matching = array_filter($fruits, function ($fruit) use ($content, $normalizer) {
return ($normalizer($fruit) == $normalizer($content));
});
if (count($matching)) {
// do your stuff...
}
Here's a clean approach. Returns unscrambled value early if found, otherwise returns null. Only returns an exact match.
function sortStringAlphabetically($stringToSort)
{
$splitString = str_split($stringToSort);
sort($splitString);
return implode($splitString);
}
function getValueFromRandomised(array $dataToSearch = [], $dataToFind)
{
$sortedDataToFind = sortStringAlphabetically($dataToFind);
foreach ($dataToSearch as $value) {
if (sortStringAlphabetically($value) === $sortedDataToFind) {
return $value;
}
}
return null;
}
$fruits = ['apple','orange','papaya','grape'];
$content = 'eaplp';
$dataExists = getValueFromRandomised($fruits, $content);
var_dump($dataExists);
// string(5) "apple"
Not found example:
$content = 'eaplpo';
var_dump($dataExists);
// NULL
Then you can use it (eg) like this:
echo !empty($dataExists) ? $dataExists . ' was found' : 'No match found';
NOTE: This is case sensitive, meaning it wont find "Apple" from "eaplp". That can be resolved by doing strtolower() on the loop's condition vars.
How about looping through the array, and using a flag to see if it matches?
$flag = false;
foreach($fruits as $fruit){
if($fruit == $content){
$flag = true;
}
}
if($flag == true){
//do something
}
I like t.m.adams answer but I also have a solution for this issue:
array_search_random(string $needle, array $haystack [, bool $strictcase = FALSE ]);
Description: Searches a string in array elements regardless of the position of the characters in the element.
needle: the caracters you are looking for as a string
haystack: the array you want to search
strictcase: if set to TRUE needle 'mood' will match 'mood' and 'doom' but not 'Mood' and 'Doom', if set to FALSE (=default) it will match all of these.
Function:
function array_search_random($needle, $haystack, $strictcase=false){
if($strictcase === false){
$needle = strtolower($needle);
}
$needle = str_split($needle);
sort($needle);
$needle = implode($needle);
foreach($haystack as $straw){
if($strictcase === false){
$straw = strtolower($straw);
}
$straw = str_split($straw);
sort($straw);
$straw = implode($straw);
if($straw == $needle){
return true;
}
}
return false;
}
if(in_array("apple", $fruits)){
true statement
}else{
else statement
}

How to check if words can be created from list of letters?

I have a string $raw="aabbcdfghmnejaachto" and an array $word_array=array('cat','rat','goat','total','egg').
My program needs to check whether it is possible to make the words in the array with letters from the string. There is one extra condition; if the word contains a letter occurring more than once, that letter must occur at least the same number of times in the string.
E.g. egg. There are two g's. If the string $raw doesn't contain two g's, then it's not possible to make this word.
This is my expected result:
Array([cat]=>'Yes',[rat]=>'No',[goat]=>'Yes',[total]=>'No',[egg]=>'No')
I tried the following, but it doesn't output the expected result:
$res=array();
$raw="aabbcdfghmnejaachto";
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
foreach($word_array as $word=>$value)
{
$word_value= str_split($value);
foreach($word_value as $w=>$w_value)
{
foreach($raw_array as $raw=>$raw_value)
{
if(strcmp($w_value,$raw_value)==0)
{
$res[$value]='Yes';
}
else
{
$res[$value]='No';
}
}
}
}
print_r($res);
EDIT: The code, as originally posted, was missing the letter e from the string $raw so the egg example would actually return No. I have updated the Question and all the Answers to reflect this. - robinCTS
You must loop through each word/element in the $words array, then loop again through each character of each word.
Upon each iteration of the outer loop, set the default result value to Yes.
Then you must iterate each unique character of the current word. (array_count_values())
Check if the number of occurrences of the current character in the word is greater than the number of occurrences of the current character in the string of letters.
*As a matter of performance optimization, array_count_values() is used on the inner loop to avoid any unnecessary iterations of duplicate letters in $word. The $count variable saves having to make two substr_count() calls in the if statement.
Code: (Demo)
$string = "aabbcdfghmnejaachto";
$words = array('cat','rat','goat','total','egg');
foreach ($words as $word) { // iterate each word
$result[$word]='Yes'; // set default result value
foreach (array_count_values(str_split($word)) as $char=>$count) { // iterate each unique letter in word
if ($count > substr_count($string, $char)) { // compare current char's count vs same char's count in $string
$result[$word]='No'; // if more of the character in word than available in $string, set No
break; // make early exit from inner loop, to avoid unnecessary iterations
}
}
}
var_export($result);
This is the output :
array (
'cat' => 'Yes',
'rat' => 'No',
'goat' => 'Yes',
'total' => 'No',
'egg' => 'No',
)
BIG THANKYOU to mickmackusa for hijacking significantly enhancing this answer.
Your problem is you are not counting the number of times each character occurs in the $raw array, you are just checking each character in each of the words to see if that character exists in $raw. Unless you put in some form of counting, or else make a copy of $raw for each word and remove letters as they are used, you are not going to be able to do this.
I have counted occurrences of characters in string and compare that number of occurrence! You can find this answer working!!!
$res=array();
$raw="aabbcdfghmnejaachto"; //tgrel -- to make all yes
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
$count_raw = array_count_values($raw_array);
foreach($word_array as $value)
{
$word_value= str_split($value);
$newArray = array_count_values($word_value);
$res[$value]='yes';
foreach($newArray as $char=>$number){
if(!isset($count_raw[$char]) || $count_raw[$char]<$number){
$res[$value]='No';
break;
}
}
}
print_r($res);
Your error here is obvious, that you decided whether a value a word is accepted or not on individual tests of characters, while it should be based on the all the letter of the word , you don't need to precise both the key and value of an array if you need only its value
as in
foreach($word_array as $value)
then I've found that the use of the function in_array(), make the code much clearer
$res=array();
$raw="aabbcdfghmnejaachto";
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
foreach($word_array as $value)
{
$word_value= str_split($value);
$res[$value]='yes';
foreach($word_value as $w_value)
{
if (!in_array($w_value,$raw_array))
$res[$value]='No';
}
}
print_r($res);
Lets try to make it w/o loops, but with closures:
$raw = "aabbcdfghmnejaachto";
$word_array = ['cat', 'rat', 'goat', 'total', 'egg'];
$result = [];
$map = count_chars($raw, 1);
array_walk(
$word_array,
function ($word) use ($map, &$result) {
$result[$word] = !array_udiff_assoc(
count_chars($word, 1), $map, function ($i, $j) { return $i > $j; }
) ? 'Yes' : 'No';
}
);
We are building a map of symbols, used in original string with count_chars($raw, 1), so it will look like this.
$map:
[
97 => 4, // "97" is a code for "a"; and "4" - occurrence number.
98 => 2,
...
]
array_walk goes through words and adds each of them in a final $result with a Yes or No values that come from a comparison with a map, that was built for a word.
array_udiff_assoc compares two maps, throwing away those elements that have the same key and values bigger for an original map (comparing with a map for a word). Also array_udiff_assoc() returns an array containing all the values from array1 that are not present in any of the other arguments, so the final step is a negation operation preceding array_udiff_assoc.
Demo
Try this
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw="aabbcrdfghmnejaachtol";
foreach($word_array as $word=>$value)
{
$raw_array= str_split($raw);
$res[$value]='Yes';
$word_value= str_split($value);
foreach($word_value as $w=>$w_value)
{
if(!in_array($w_value,$raw_array))
{
$res[$value]='No';
}
else
{
unset($raw_array[array_search($w_value, $raw_array)]);
}
}
}
This will not allow character again, if it is used once Like "total".
We can check to see if each letter from each word is within the letters given, and pluck found letters out as we go.
The function below short circuits if a letter is not found.
<?php
function can_form_word_from_letters($word, $letters) {
$letters = str_split($letters);
$word_letters = str_split($word);
foreach($word_letters as $letter) {
$key = array_search($letter, $letters);
if($key === false) return;
unset($letters[$key]); // Letter found, now remove it from letters.
}
return true;
}
$letters = "aabbcdfghmnejaachto";
$words = array('cat','rat','goat','total','egg');
foreach($words as $word) {
$result[$word] = can_form_word_from_letters($word, $letters) ? 'Yes' : 'No';
}
var_dump($result);
Output:
array (size=5)
'cat' => string 'Yes' (length=3)
'rat' => string 'No' (length=2)
'goat' => string 'Yes' (length=3)
'total' => string 'No' (length=2)
'egg' => string 'No' (length=2)

similar substring in other string PHP

How to check substrings in PHP by prefix or postfix.
For example, I have the search string named as $to_search as follows:
$to_search = "abcdef"
And three cases to check the if that is the substring in $to_search as follows:
$cases = ["abc def", "def", "deff", ... Other values ...];
Now I have to detect the first three cases using substr() function.
How can I detect the "abc def", "def", "deff" as substring of "abcdef" in PHP.
You might find the Levenshtein distance between the two words useful - it'll have a value of 1 for abc def. However your problem is not well defined - matching strings that are "similar" doesn't mean anything concrete.
Edit - If you set the deletion cost to 0 then this very closely models the problem you are proposing. Just check that the levenshtein distance is less than 1 for everything in the array.
This will find if any of the strings inside $cases are a substring of $to_search.
foreach($cases as $someString){
if(strpos($to_search, $someString) !== false){
// $someString is found inside $to_search
}
}
Only "def" is though as none of the other strings have much to do with each other.
Also on a side not; it is prefix and suffix not postfix.
To find any of the cases that either begin with or end with either the beginning or ending of the search string, I don't know of another way to do it than to just step through all of the possible beginning and ending combinations and check them. There's probably a better way to do this, but this should do it.
$to_search = "abcdef";
$cases = ["abc def", "def", "deff", "otherabc", "noabcmatch", "nodefmatch"];
$matches = array();
$len = strlen($to_search);
for ($i=1; $i <= $len; $i++) {
// get the beginning and end of the search string of length $i
$pre_post = array();
$pre_post[] = substr($to_search, 0, $i);
$pre_post[] = substr($to_search, -$i);
foreach ($cases as $case) {
// get the beginning and end of each case of length $i
$pre = substr($case, 0, $i);
$post = substr($case, -$i);
// check if any of them match
if (in_array($pre, $pre_post) || in_array($post, $pre_post)) {
// using the case as the array key for $matches will keep it distinct
$matches[$case] = true;
}
}
}
// use array_keys() to get the keys back to values
var_dump(array_keys($matches));
You can use array_filter function like this:
$cases = ["cake", "cakes", "flowers", "chocolate", "chocolates"];
$to_search = "chocolatecake";
$search = strtolower($to_search);
$arr = array_filter($cases, function($val) use ($search) { return
strpos( $search,
str_replace(' ', '', preg_replace('/s$/', '', strtolower($val))) ) !== FALSE; });
print_r($arr);
Output:
Array
(
[0] => cake
[1] => cakes
[3] => chocolate
[4] => chocolates
)
As you can it prints all the values you expected apart from deff which is not part of search string abcdef as I commented above.

Categories