String Combinations Matching - php

Suppose a string:
$str = 'a_b_c';
I want match all possible combination with a, b, c with above. For example:
b_a_c, c_a_b, a_c_b..etc will be give true when compare with above $str.
NOTE:
$str may be random. eg: a_b, k_l_m_n etc

I would split your string into an array, and then compare it to an array of elements to match on.
$originalList = explode('_', 'a_b_c');
$matchList = array('a', 'b', 'c');
$diff = array_diff($matchList, $originalList);
if (!empty($diff)) {
// At least one of the elements in $matchList is not in $originalList
}
Beware of duplicate elements and what not, depending on how your data comes in.
Documentation:
array_diff()
explode()

There is no builtin way to quickly do this. Your task can be accomplished many different ways which will vary on how general they are. You make no mention of null values or checking the formatting of the string, so something like this might work for your purpose:
function all_combos($str,$vals) {
$s=explode("_",$str);
foreach($s as $c) {
if(!in_array($s,$vals)) return false;
}
return true;
}
Call like all_combos("b_c_a",array("a","b","c"));

Related

Finding All Possible Combinations of Strings with Restrictions

I need help with creating an algorithm in PHP that, given an array of alphabets (represented as strings) and an array of groupings of those alphabets (also an array of strings), returns an array of arrays of all possible combinations of strings based on those groupings. The following example will make it clear -
If the input array is ['A', 'B', 'C'] and the groupings are ['AB', 'BC'] the returned output:
Without any restrictions would be
[['A','B','C'], ['AB,'C'], ['A','BC'], ['AC','B'], ['ABC']]
With the restrictions of the groupings should be [['A','B','C'], ['AB,'C'], ['A','BC']]
The reason for this is because neither 'ABC' nor 'AC' are allowed groupings and the idea is that the groupings should only exist if they belong to the specified array. In this case, since 'AB' and 'BC' are the only possible groupings, the output contains them. The first output was just for demonstration purposes, but the algorithm should produce the second output. The only other restriction is that there can't be duplicate alphabets in a single combination. So the following output is NOT correct:
[['A','B','C'], ['AB,'C'], ['A','BC'], ['AB','BC'], ['AC','B'], ['ABC']]
since 'B' is a duplicate in ['AB','BC']
A similar question I found was here, except that there are no restrictions on which numbers can be grouped together in the "Result" in this question.
I apologize if I made it sound confusing but I'll be sure to clarify if you have any questions.
The simplest approach to generate such partitions is recursive (I think).
At first, represent restrictions as boolean (or 0/1) 2d matrix. For your case graph has connections (edges) A-B and B-C and adjacency matrix is [[0,1,0][1,0,1],[0,1,0]]
Start from empty array. At every recursion level add next element (A, then B, then C) into all possible groups and into separate group.
(In languages like C I'd use bit masks for every group to determine quickly with bit-OR operation whether a group allows to add current element)
First level: add A and get:
[[A]]
Second level: add B both in existing group and in separate one:
[[A, B]], [[A],[B]]
Third Level: you add C only with:
[[A, B], C], [[A],[B, C]], [[A],[B], [C]]
You can use the answer from the post you linked. I adapted it for you:
function generate_groups($collection) {
if (count($collection) == 1) {
yield [$collection];
return;
}
$first = $collection[0];
foreach (generate_groups(array_slice($collection, 1)) as $smaller) {
foreach (array_values($smaller) as $n => $subset) {
yield array_merge(
array_slice($smaller, 0, $n),
[array_merge([$first], $subset)],
array_slice($smaller, $n+1)
);
}
yield array_merge([[$first]], $smaller);
}
}
$input = ['A', 'B', 'C'];
$groupings = ['AB', 'BC'];
foreach (generate_groups($input) as $groups) {
$are_groups_ok = true;
foreach ($groups as $group) {
$compact = implode($group);
if (strlen($compact) != 1 and !in_array($compact, $groupings)) {
$are_groups_ok = false;
}
}
if ($are_groups_ok) {
echo "[" . implode("], [", array_map("implode", $groups)) . "]\n";
}
}
This prints:
[A], [BC]
[AB], [C]
[A], [B], [C]

How to change order of substrings inside a larger string?

This is fairly confusing, but I'll try to explain as best I can...
I've got a MYSQL table full of strings like this:
{3}12{2}3{5}52
{3}7{2}44
{3}15{2}2{4}132{5}52{6}22
{3}15{2}3{4}168{5}52
Each string is a combination of product options and option values. The numbers inside the { } are the option, for example {3} = Color. The number immediately following each { } number is that option's value, for example 12 = Blue. I've already got the PHP code that knows how to parse these strings and deliver the information correctly, with one exception: For reasons that are probably too convoluted to get into here, the order of the options needs to be 3,4,2,5,6. (To try to modify the rest of the system to accept the current order would be too monumental a task.) It's fine if a particular combination doesn't have all five options, for instance "{3}7{2}44" delivers the expected result. The problem is just with combinations that include option 2 AND option 4-- their order needs to be switched so that any combination that includes both options 2 and 4, the {4} and its corresponding value comes before the {2} and it's corresponding value.
I've tried bringing the column into Excel and using Text to Columns, splitting them up by the "{" and "}" characters and re-ordering the columns, but since not every string yields the same number of columns, the order gets messed up in other ways (like option 5 coming before option 2).
I've also experimented with using PHP to explode each string into an array (which I thought I could then re-sort) using "}" as the delimiter, but I had no luck with that either because then the numbers blend together in other ways that make them unusable.
TL;DR: I have a bunch of strings like the ones quoted above. In every string that contains both a "{2}" and a "{4}", the placement of both of those values needs to be switched, so that the {4} and the number that follows it comes before the {2} and the number that follows it. In other words:
{3}15{2}3{4}168{5}52
needs to become
{3}15{4}168{2}3{5}52
The closest I've been able to come to a solution, in pseudocode, would be something like:
for each string,
if "{4}" is present in this string AND "{2}" is present in this string,
take the "{4}" and every digit that follows it UNTIL you hit another "{" and store that substring as a variable, then remove it from the string.
then, insert that substring back into the string, at a position starting immediately before the "{2}".
I hope that makes some kind of sense...
Is there any way with PHP, Excel, Notepad++, regular expressions, etc., that I can do this? Any help would be insanely appreciated.
EDITED TO ADD: After several people posted solutions, which I tried, I realized that it would be crucial to mention that my host is running PHP 5.2.17, which doesn't seem to allow for usort with custom sorting. If I could upvote everyone's solution (all of which I tried in PHP Sandbox and all of which worked), I would, but my rep is too low.
How would something like this work for you. The first 9 lines just transform your string into an array with each element being an array of the option number and value. The Order establishes an order for the items to appear in and the last does a usort utilizing the order array for positions.
$str = "{3}15{2}2{4}132{5}52{6}22";
$matches = array();
preg_match_all('/\{([0-9]+)\}([0-9]+)/', $str, $matches);
array_shift($matches);
$options = array();
for($x = 0; $x < count($matches[0]); $x++){
$options[] = array($matches[0][$x], $matches[1][$x]);
}
$order = [3,4,2,5,6];
usort($options, function($a, $b) use ($order) {
return array_search($a[0], $order) - array_search($b[0], $order);
});
To get you data back into the required format you would just
$str = "";
foreach($options as $opt){
$str.="{".$opt[0]."}".$opt[1];
}
On of the bonuses here is that when you add a new options type inserting adjusting the order is just a matter of inserting the option number in the correct position of the $order array.
First of all, those options should probably be in a separate table. You're breaking all kinds of normalization rules stuffing those things into a string like that.
But if you really want to parse that out in php, split the string into a key=>value array with something like this:
$options = [];
$pairs = explode('{', $option_string);
foreach($pairs as $pair) {
list($key,$value) = explode('}', $pair);
$options[$key] = $value;
}
I think this will give you:
$options[3]=15;
$options[2]=3;
$options[4]=168;
$options[5]=52;
Another option would be to use some sort of existing serialization (either serialize() or json_encode() in php) instead of rolling your own:
$options_string = json_encode($options);
// store $options_string in db
then
// get $options_string from db
$options = json_decode($options_string);
Here's a neat solution:
$order = array(3, 4, 2, 5, 6);
$string = '{3}15{2}3{4}168{5}52';
$split = preg_split('#\b(?={)#', $string);
usort($split, function($a, $b) use ($order) {
$a = array_search(preg_replace('#^{(\d+)}\d+$#', '$1', $a), $order);
$b = array_search(preg_replace('#^{(\d+)}\d+$#', '$1', $b), $order);
return $a - $b;
});
$split = implode('', $split);
var_dump($split);

PHP - Matching words in dynamic arrays

I've taken a look around but cant seem to find anything that does as needed.
Lets say I have 2 arrays in a function, however they are completely dynamic. So each time this function is run, the arrays are created based on a page that has been submitted.
I need to some how match these arrays and look for any phrase/words that appear in both.
Example: (with only a single element in each array)
Array 1: "This is some sample text that will display on the web"
Array 2: "You could always use some sample text for testing"
So in that example, the 2 arrays have a phrase that appears exactly the same in each: "Sample Text"
So seeing as these arrays are always dynamic I am unable to do anything like Regex because I will never know what words will be in the arrays.
You could find all words in an array of strings like this:
function find_words(array $arr)
{
return array_reduce($arr, function(&$result, $item) {
if (($words = str_word_count($item, 1))) {
return array_merge($result, $words);
}
}, array());
}
To use it, you run the end results through array_intersect:
$a = array('This is some sample text that', 'will display on the web');
$b = array('You could always use some sample text for testing');
$similar = array_intersect(find_words($a), find_words($b));
// ["some", "sample", "text"]
Array_intersect() should do this for you:
http://www.php.net/manual/en/function.array-intersect.php
*array_intersect() returns an array containing all the values of array1 that are present in all the arguments. Note that keys are preserved.*
maybe something like this:
foreach($arr as $v) {
$pos = strpos($v, "sample text");
if($pos !== false) {
// success
}
}
here is the manual:
http://de3.php.net/manual/de/function.strpos.php
Explode the two strings by spaces, and it is a simple case of comparing arrays.

Need every permutation of capitalized letters in php

I want to build an array in php that contains every possible capitalization permutation of a word. so it would be (pseudocode)
function permutate($word){
for ($i=0; $i<count($word); $i++){
...confused here...
array_push($myArray, $newWord)
}
return $myArray;
}
So say I put in "School" I should get an array back of
{school, School, sChool, SCHool, schOOl, ... SCHOOL}
I know of functions that capitalize the string or the first character, but I am really struggling with how to accomplish this.
This should do it for you:
function permute($word){
if(!$word)
return array($word);
$permutations = array();
foreach(permute(substr($word, 1)) as $permutation){
$lower = strtolower($word[0]);
$permutations[] = $lower . $permutation;
$upper = strtoupper($word[0]);
if($upper !== $lower)
$permutations[] = $upper . $permutation;
}
return $permutations;
}
Codepad Demo
However, for your particular use case there may be a better solution. As there are 2^n permutations for a string of length n. It will be infeasible to run this (or even to generate all those strings using any method at all) on a much longer string.
In reality you should probably be converting strings to one particular case before hashing them, before storing them in the database, if you want to do case-insensitive matching.

convert string to php arguments

so suppose I have a function:
function j($a, $b){
return $a + $b;
}
and then I put the intended arguments of the function into a string:
$str = '1,3';
is there a way to make the function treat the single string argument as if it were the arguments that the programmer inserted into the function....so when you do
j($str),
instead of having the function treat the $str as a single string argument, it fetches the content of the string and treats it as if the programmer wrote j(1,3) instead of j($str)
also this is a rather simple example, but I'd like it to work for even more complicated argument strings involving arrays, multidimensional arrays, associative arrays, array within arrays, as well as string arguments that have commas in it (so just exploding by comma is not really feasible)
also I'd rather not use eval() in the solution
EDIT
Also I'm trying to get this to work on any function not just mine (and not just this specific function which is just a worthless example function) so preferably the operation is to be done outside of the function
call_user_func_array('j', explode(',', $str));
http://www.php.net/call_user_func_array
I have no idea how you want to make this work for "more complex argument strings including arrays of arrays", since it's hard to express those as strings. If you can format whatever string you have into an array though, for example using JSON strings and json_decode, call_user_func_array is your friend.
This should work for a single, comma-separated string:
function j($str){
list($a, $b) = explode(',', $str);
return $a + $b;
}
What do you want to sum in a multi-dimensional array? All of the values?
If yes: You only have to check the type of your argument (e.g. using is_array()) and then iterate through it. When it is multi-dimensional, call your function recursively.
make all parameter but except the first one optional and then use list() and explode() if the first parameter is a string (or contains ,):
function j($a, $b=null){
if(strpos($a,',')!==false){
list($a,$b) = explode(',',$a)
}
return $a + $b;
}
this is just a basic example, but the principle should be clear:
check if one of the arguments is composed of multiple parameters
if so, parse it on your own to get the single parameters
function j($a, $b = 0){ // make second arg optional
if (! $b) { // is second arg specified and not zero
if (strpos($a, ',') !== false){ // has provided first arg a comma
list($first, $second) = explode(',' $a); // yes then get two values from it
return $first + $second; // return the result
}
}
else {
return $a + $b; // two args were passed, return the result
}
}
Now your function will support both formats, with one argument eg:
$str = '1,3'
j($str);
as well as two arguments:
j(5, 10);
This works :)
function f($str, $delimiter = ';')
{
$strargs = explode($delimiter, $str);
$args = array();
foreach($strargs as $item)
eval("\$args[] = " . $item. ";");
// $args contains all arguments
print_r($args);
}
Check it:
f("6;array(8,9);array(array(1,0,8), 5678)");
Most of the answers assume, that everything is nicely separated with coma ",", but it's not always the case. For example there could be different variable types, even strings with coma's.
$values = "123, 'here, is, a, problem, that, can\'t, be, solved, with, explode() function, mkay?'";
This can be handled with eval() and dot's "..." args retrieval in php 7.
function helper_string_args(...$args) {
return $args;
}
$func = "\$values = \\helper_string_args($values);";
try {
eval($func);
} catch (Exception $e) {
var_dump($e);
exit;
}

Categories