el Dude
el Dude

Reputation: 5183

preg_replace() Remove repeating characters and replace them with the corresponding characters?

$s='123///456***789';

now I try to replace repeating /// and ***

$s=preg_replace('!\/+!',"/",$s);
$s=preg_replace('!\*+!',"*",$s);

The result is 123/456*789 Ok

I'm trying to remove repeatings with the one pattern but I can't get how to set corresponding character for each repeating character

$s=preg_replace('![\/\*]+!',"/",$s);

The result is 123/456/789 but I need it to be like the above result - 123/456*789

Upvotes: 1

Views: 270

Answers (2)

rkhb
rkhb

Reputation: 14409

Using back references (https://www.php.net/manual/en/regexp.reference.back-references.php):

$s='123///456***789';
$s = preg_replace ('~([\/\*])\1+~', '\1', $s);
printf ("%s\n", $s);

Upvotes: 2

dognose
dognose

Reputation: 20899

You can use a preg_replace_callback to achieve that:

$s=preg_replace_callback('!(\*+|\/+)!' ,
  function($match){
    //whatever we match MULTIPLE times - replace it with one time "that".
    return substr($match[1],0,1); //first matchgroup
  }
,$s);

Side note: The Pattern ![\/\*]+! will also match /*/*/* - which is not what you (maybe) want to achieve. You should use (\*+|\/+) instead.

Side note 2: Inside MatchGroups you do not need to escape. [/*]+ would be equal to the regex you provided.


If you design the pattern a little more tricky, you can ommit the callback, and work with a backreference:

$s=preg_replace('!(?:(\*)\*+|(\/)\/+)!' , "$1$2", $s);

Explanation:

this matches one time either * or /, followed by 1 or more of them. Your first matchgroup (respectively second) will now contain only ONE of the sign in question. Therefore, the whole match of *** will be replaced with your first (respectively second) match group - which is a single * (respectively /) now.

using $1$2 as replacement is safe, because due to the OR (|) One of those matchgroups is ALWAYS empty.

But i'd prefer solution one, as it is way clearer.

Upvotes: 1

Related Questions