Here are two versions that I could come up with.
The first uses a regular expression and replaces duplicate matches of the $needle
string with a single $needle
string. This is the most vigorously tested version and handles all possibilities of inputs successfully (as far as I know).
function str_shrink( $str, $needle)
{
if( is_array( $needle))
{
foreach( $needle as $n)
{
$str = str_shrink( $str, $n);
}
return $str;
}
$regex = '/(' . $needle . ')(?:' . $needle . ')+/i';
return preg_replace_callback( $regex, function( $matches) { return $matches[1] . '(x' . substr_count( $matches[0], $matches[1]) . ')'; }, $str);
}
The second uses string manipulation to continually replace occurrences of the $needle
concatenated with itself. Note that this one will fail if $needle.$needle
occurs more than once in the input string (The first one does not have this problem).
function str_shrink2( $str, $needle)
{
if( is_array( $needle))
{
foreach( $needle as $n)
{
$str = str_shrink2( $str, $n);
}
return $str;
}
$count = 1; $previous = -1;
while( ($i = strpos( $str, $needle.$needle)) > 0)
{
$str = str_replace( $needle.$needle, $needle, $str);
$count++;
$previous = $i;
}
if( $count > 1)
{
$str = substr( $str, 0, $previous) . $needle .'(x' . $count . ')' . substr( $str, $previous + strlen( $needle));
}
return $str;
}
See them both in action
Edit: I didn't realize that the desired output wanted to include the number of repetitions. I've modified my examples accordingly.