views:

76

answers:

5

Hello !

I have two strings:

$a = '/srv/http/projects/name';
$b = '/projects/name/some/dir';

And I would like to get a merged string with not repeated common part:

$c = '/srv/http/projects/name/some/dir';

Is there any effective way to get it ?

+1  A: 

It's kinda ugly, and assumes your strings always start with '/'... but:

$a = '/srv/http/projects/name';
$b = '/projects/name/some/dir';

$merged = array_merge(explode('/', $a), explode('/', $b) );
$unique = array_unique($merged);

$c = implode('/', $unique);

print $c; // prints "/srv/http/projects/name/some/dir"
Owen
Does it work for a URL like `$a = '/srv/http/projects/name/http;` and `$b = '/projects/name/http/some/dir;`?
Chacha102
Nice approach. This does assume that no directory name appears twice. For a resulting path such as /www/one/two/www/ this would not work.
Cryo
For `$a = '/name';` and `$b = '/projects/name/some/dir';` it will give `$c = '/name/projects/some/dir';` so it will not works properly.
hsz
@hsz - That example violates your requirements that there is a common middle part.
Sonny
+1  A: 

function f($a, $b)
{
  for($i=0; count($a) > $i ; $i++)
  {
    if(strpos($b, substr($a, $i)) !== FALSE)
      return substr($a, 0, $i-1).$b;
  } 
  return $a.$b;
}
Adelf
+1  A: 
Cryo
Your method cuts off some of the path. `$a = '/srv/http/projects/name/http/';`, `$b = '/projects/name/http/some/dir';` so `/srv/http/projects/name/http/ome/dir ` gets returned. Notice the **ome**. This could be from my end, by try it out and let me know if you get similar results.
Anthony Forloney
@Anthony Forloney: That was due to an OBO bug in my original post, already updated my answer with a fix, that new version works with your two values correctly.
Cryo
A: 

Try this:

function merge($a, $b) {
    // divide into path parts to compare the parts
    $start = preg_split('%/%', $a, -1, PREG_SPLIT_NO_EMPTY);
    $end = preg_split('%/%', $b, -1, PREG_SPLIT_NO_EMPTY);

    // if the first part of the first path is in the second path than switch
    if(in_array($start[0], $end)) {
       $temp = $start;
       $start = $end;
       $end = $temp;
    }
    $parts = array();
    // get the index of the last part of the first path in the second path
    $index = array_search($start[count($start)-1], $end);

    // if the part exists, remove the first parts of the second path
    if($index !== false) {
        $parts = array_merge($start, array_slice($end, $index+1));
    }
    return '/' . join('/', $parts);
}


$a = '/srv/http/projects/name';
$b = '/projects/name/some/dir';

print merge($a, $b);

This gives me:

/srv/http/projects/name/some/dir

You might have to provide a default value or whatever if the path have no common part.

Felix Kling
A: 

I don't think there's a "smart" way to do that. Just iterate over $a until all of the rightmost tokens match the same number of tokens at the beginning of $b.

Here I explode() both strings so that I can easily capture the right number of tokens via array_slice().

$a = '/srv/http/projects/name/http';
$b = '/projects/name/http/some/dir';

var_dump(merge_path($a, $b));

function merge_path($path1, $path2)
{
    $p1 = explode('/', trim($path1,' /'));
    $p2 = explode('/', trim($path2,' /'));

    $len = count($p1);

    do
    {
        if (array_slice($p1, -$len) === array_slice($p2, 0, $len))
        {
            return '/'
                 . implode('/', array_slice($p1, 0, -$len))
                 . '/'
                 . implode('/', $p2);
        }
    }
    while (--$len);

    return false;
}
Josh Davis