built in function to combine overlapping string sequences in php? - php

Is there a built in function in PHP that would combine 2 strings into 1?
Example:
$string1 = 'abcde';
$string2 = 'cdefg';
Combine to get: abcdefg.
If the exact overlapping sequence and the position are known, then it is possible to write a code to merge them.
TIA

I found the substr_replace method to return funny results.
Especially when working with url strings. I just wrote this function.
It seems to be working perfectly for my needs.
The function will return the longest possible match by default.
function findOverlap($str1, $str2){
$return = array();
$sl1 = strlen($str1);
$sl2 = strlen($str2);
$max = $sl1>$sl2?$sl2:$sl1;
$i=1;
while($i<=$max){
$s1 = substr($str1, -$i);
$s2 = substr($str2, 0, $i);
if($s1 == $s2){
$return[] = $s1;
}
$i++;
}
if(!empty($return)){
return $return;
}
return false;
}
function replaceOverlap($str1, $str2, $length = "long"){
if($overlap = findOverlap($str1, $str2)){
switch($length){
case "short":
$overlap = $overlap[0];
break;
case "long":
default:
$overlap = $overlap[count($overlap)-1];
break;
}
$str1 = substr($str1, 0, -strlen($overlap));
$str2 = substr($str2, strlen($overlap));
return $str1.$overlap.$str2;
}
return false;
}
Usage to get the maximum length match:
echo replaceOverlap("abxcdex", "xcdexfg"); //Result: abxcdexfg
To get the first match instead of the last match call the function like this:
echo replaceOverlap("abxcdex", "xcdexfg", “short”); //Result: abxcdexcdexfg
To get the overlapping string just call:
echo findOverlap("abxcdex", "xcdexfg"); //Result: array( 0 => "x", 1 => "xcdex" )

It's possible using substr_replace() and strcspn():
$string1 = 'abcde';
$string2 = 'cdefgh';
echo substr_replace($string1, $string2, strcspn($string1, $string2)); // abcdefgh

No, there is no builtin function, but you can easily write one yourself by using substr and a loop to see how much of the strings that overlap.

Related

String between string with array in PHP, array order ISSUE

I'm facing an issue with a function that gets a string between two other strings.
function string_between($str, $starting_word, $ending_word) {
$subtring_start = strpos($str, $starting_word);
$subtring_start += strlen($starting_word);
foreach ($ending_word as $a){
$size = strpos($str, $a, $subtring_start) - $subtring_start;
}
return substr($str, $subtring_start, $size);
}
The issue is that the function searches for the first ending_word in the array.
An example will be easier to understand:
$array_a = ['the', 'amen']; // Starting strings
$array_b = [',', '.']; // Ending strings
$str = "Hello, the world. Then, it is over.";
Expected result:
"the world."
Current result:
"the world. Then,"
The function will think that the ending_word is "," because it is the first element met in the array_b. However, the text encounters first the '.' after the "the" starting word.
How can I make sure the function goes through the text and stops at the first element in the $str present in the array_b, whatever the position in the array?
Any idea?
Basically, you need to break outside of your foreach loop when $size > 0
That way it stops looping through your array when it finds the 1st occurrence. Here is the more complete code with other fixes:
function stringBetween($string, $startingWords, $endingWords) {
foreach ($startingWords as $startingWord) {
$subtringStart = strpos($string, $startingWord);
if ($subtringStart > 0) {
foreach ($endingWords as $endingWord){
$size = strpos($string, $endingWord, $subtringStart) - $subtringStart + strlen($endingWord);
if ($size > 0) {
break;
}
}
if ($size > 0) {
return substr($string, $subtringStart, $size);
}
}
}
return null;
}
$startArr = array('the', 'amen'); // Starting strings
$endArr = array('.', ','); // Ending strings
$str = "Hello, the world. Then, it is over.";
echo stringBetween($str, $startArr, $endArr); // the world.
This type of problems are best solved by PCRE regexes, only couple of lines needed in function :
function string_between($str, $starts, $ends) {
preg_match("/(?:{$starts}).*?(?:{$ends})/mi", $str, $m);
return $m[0];
}
Then calling like this :
echo string_between("Hello, the world. Then, it is over.", 'the|amen', ',|\.');
Produces : the world.
The trick,- search to the nearest matching ending symbol is done with regex non-greedy seach, indicated by question symbol in pattern .*?. You can even extend this function to accept arrays as starting/ending symbols, just that case modify function (possibly with implode('|',$arr)) for concatenating symbols into regex grouping formula.
Edited version
This works now. Iterate over your teststrings from first array looking for position of occurance from teststring. If found one then search for the second teststring at startposition from end of first string.
To get the shortest hit I store the position from the second and take the minimum.
You can try it at http://sandbox.onlinephpfunctions.com/code/0f1e5c97da62b4daaf0e49f52271fe288d1cacbb
$array_a =array('the','amen');
$array_b =array(',','.', '#');
$str = "Hello, the world. Then, it is over.";
function earchString($str, $array_a, $array_b) {
forEach($array_a as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($array_b as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
echo earchString($str, $array_a, $array_b);

PHP Match String Pattern and Get Variable

I looked up some reference like this question and this question but could not figure out what I need to do.
What I am trying to do is:
Say, I have two strings:
$str1 = "link/usa";
$str2 = "link/{country}";
Now I want to check if this the pattern matches. If they match, I want the value of country to be set usa.
$country = "usa";
I also want it to work in cases like:
$str1 = "link/usa/texas";
$str2 = "link/{country}/{place}";
Maybe integers as well. Like match every braces and provide the variable with value. (And, yes better performance if possible)
I cannot get a work around since I am very new to regular expresssions. Thanks in advance.
It will give you results as expected
$str1 = "link/usa";
$str2 = "link/{country}";
if(preg_match('~link/([a-z]+)~i', $str1, $matches1) && preg_match('~link/{([a-z]+)}~i', $str2, $matches2)){
$$matches2[1] = $matches1[1];
echo $country;
}
Note: Above code will just parse alphabets, you can extend characters in range as per need.
UPDATE:
You can also do it using explode, see example below:
$val1 = explode('/', $str1);
$val2 = explode('/', $str2);
${rtrim(ltrim($val2[1],'{'), '}')} = $val1[1];
echo $country;
UPDATE 2
$str1 = "link/usa/texas/2/";
$str2 = "/link/{country}/{city}/{page}";
if(preg_match_all('~/([a-z0-9]+)~i', $str1, $matches1) && preg_match_all('~{([a-z]+)}~i', $str2, $matches2)){
foreach($matches2[1] as $key => $matches){
$$matches = $matches1[1][$key];
}
echo $country;
echo '<br>';
echo $city;
echo '<br>';
echo $page;
}
I don't see the point to use the key as variable name when you can built an associative array that will be probably more handy to use later and that avoids to write ugly dynamic variable names ${the_name_of_the_var_${of_my_var_${of_your_var}}}:
$str1 = "link/usa/texas";
$str2 = "link/{country}/{place}";
function combine($pattern, $values) {
$keys = array_map(function ($i) { return trim($i, '{}'); },
explode('/', $pattern));
$values = explode('/', $values);
if (array_shift($keys) == array_shift($values) && count($keys) &&
count($keys) == count($values))
return array_combine($keys, $values);
else throw new Exception ("invalid format");
}
print_r(combine($str2, $str1));

match two strings and compare each letter in php

I googled this question I can't to find the exact solution...
I have 2 variables...
$s1 = "ABC"; //or "BC"
$s2 = "BC"; //or "Bangalore"
I have to compare $s1 and $s2 and give the output as letters which is not present in $s2
eg : "A" // or"C"
Like that
I have to compare $s2 and $s1 and give the output as letters which is not present in $s1
eg : null // or"angalore"
What I tried..
I spit the strings to array...
Using nested for loop to find the non matched letters...
I wrote code more than 35 lines..
But no result :(
Please help me ......
echo str_ireplace(str_split($s2), "", $s1); // output: A
You can use array_diff() here:
function str_compare($str1, $str2)
{
$str1chars = str_split($str1);
$str2chars = str_split($str2);
$diff = array_diff($str1chars, $str2chars)
return implode($diff);
}
By calling the function as follows:
$diffchars = str_compare('ABC', 'BC');
You will receive a string containing the characters that do not appear in both strings. In this example, it'll be A, because that character appears in $str1, but not in $str2.
You can use str_split and array_diff like :
<?php
$s1 = 'abcedf';
$s2 = 'xzcedf5460gf';
print_r(array_diff(str_split($s1), str_split($s2)));
Use array_diff():
function str_diff($str1, $str2) {
$arr1 = str_split($str1);
$arr2 = str_split($str2);
$diff = array_diff($arr1, $arr2);
return implode($diff);
}
Usage:
echo str_diff('BC', 'Bangalore'); // => C
echo str_diff('ABC', 'BC'); // => A
Ok to do this
$str1s = "abc";
$str2s = "BCd";
function findNot($str1, $str2, $asArray = false){
$returnValue = array_diff(array_unique(str_split(strtolower($str1))), array_unique(str_split(strtolower($str2))));
if($asArray == false){
return implode($returnValue);
}else{
return $returnValue;
}
}
echo findNot($str1s, $str2s); //gives a string
echo findNot($str1s, $str2s, true); //gives array of characters
This allows you to return as either array or string.

Find string at specific position in array - PHP

I have the following text string: "Gardening,Landscaping,Football,3D Modelling"
I need PHP to pick out the string before the phrase, "Football".
So, no matter the size of the array, the code will always scan for the phrase 'Football' and retrieve the text immediately before it.
Here is my (lame) attempt so far:
$array = "Swimming,Astronomy,Gardening,Rugby,Landscaping,Football,3D Modelling";
$find = "Football";
$string = magicFunction($find, $array);
echo $string; // $string would = 'Landscaping'
Any help with this would be greatly appreciated.
Many thanks
$terms = explode(',', $array);
$index = array_search('Football', $terms);
$indexBefore = $index - 1;
if (!isset($terms[$indexBefore])) {
trigger_error('No element BEFORE');
} else {
echo $terms[$indexBefore];
}
//PHP 5.4
echo explode(',Football', $array)[0]
//PHP 5.3-
list($string) = explode(',Football', $array);
echo $string;
$array = array("Swimming","Astronomy","Gardening","Rugby","Landscaping","Football","3D" "Modelling");
$find = "Football";
$string = getFromOffset($find, $array);
echo $string; // $string would = 'Landscaping'
function getFromOffset($find, $array, $offset = -1)
{
$id = array_search($find, $array);
if (!$id)
return $find.' not found';
if (isset($array[$id + $offset]))
return $array[$id + $offset];
return $find.' is first in array';
}
You can also set the offset to be different from 1 previous.

preg_replace to match all but first occurance of something?

I'm looking for a way to replace all but first occurrences of a group or some character.
For example a following random string:
+Z1A124B555ND124AB+A555
1,5,2,4,A,B and + are repeating through out the string.
124, 555 are groups of characters that are also reoccurring.
Now, let's say I want to remove every but first occurrence of 555, A and B.
What regex would be appropriate? I could think of an example replacing all:
preg_replace('/555|A|B/','',$string);
Something like ^ that, but I want to keep the first occurrence... Any ideas?
Are your strings always delimited by plus signs? Do 555, A, and B always occur in the first "group" (delimited by +)?
If so, you can split, replace and then join:
$input = '+Z1A124B555+A124AB+A555';
$array = explode('+', $input, 3); // max 3 elements
$array[2] = str_replace(array('555', 'A', 'B'), '', $array[2]);
$output = implode('+', $array);
ps. No need to use regexes, when we can use a simple str_replace
Use the preg_replace_callback function:
$replaced = array('555' => 0, 'A' => 0, 'B' => 0);
$input = '+Z1A124B555+A124AB+A555';
$output = preg_replace_callback('/555|[AB]/', function($matches) {
static $replaced = 0;
if($replaced++ == 0) return $matches[0];
return '';
}, $input);
This solution could be modified to do what you want: PHP: preg_replace (x) occurrence?
Here is a modified solution for you:
<?php
class Parser {
private $i;
public function parse($source) {
$this->i=array();
return preg_replace_callback('/555|A|B/', array($this, 'on_match'), $source);
}
private function on_match($m) {
$first=$m[0];
if(!isset($this->i[$first]))
{
echo "I'm HERE";
$this->i[$first]=1;
}
else
{
$this->i[$first]++;
}
// Return what you want the replacement to be.
if($this->i[$first]>1)
{
$result="";
}
else
{
$result=$m[0];
}
return $result;
}
}
$sample = '+Z1A124B555ND124AB+A555';
$parse = new Parser();
$result = $parse->parse($sample);
echo "Result is: [$result]\n";
?>
A more generic function that works with every pattern.
function replaceAllButFirst($pattern, $replacement, $subject) {
return preg_replace_callback($pattern,
function($matches) use ($replacement, $subject) {
static $s;
$s++;
return ($s <= 1) ? $matches[0] : $replacement;
},
$subject
);
}

Categories