2

I want to replace equal number of unmatched characters with *. Like as I've string

xyzdsdasdas@xyss.com

should be replace into

x*********s@x**s.com

Right now just for work around I'm using the following regex

^(\w).*?(.@.).*?(.\.\w+)

So using that followed regex along with preg_replace like as

echo preg_replace('/^(\w).*?(.@).*?(\.\w+)/', "$1****$2****$3", "xyzdsdasdas@xyss.com");

which result into

x****s@x****s.com

but what I want to achieve over here is

x*********s@x**s.com

Demo

Narendrasingh Sisodia
  • 21,247
  • 6
  • 47
  • 54

4 Answers4

3

I would use (*SKIP)(*F)

preg_replace('~(?:^.|.@.|.\.\w+$)(*SKIP)(*F)|.~', '*', $str);

DEMO

  • First match all the chars you don't want. ie, (?:^.|.@.|.\.\w+$)
  • Now, skip those matches using (*SKIP)(*F)
  • | OR
  • Now the dot after | will match all the characters other than the skipped ones.
Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
  • Its working fine but I didn't understand `(*SKIP)(*F)|.` part of the regex –  Oct 02 '15 at 09:50
  • 1
    Great Explanation. @Avi +1 – Narendrasingh Sisodia Oct 02 '15 at 09:52
  • @Avinash Raj, I've learnt something today. `(*SKIP)` and `(*F)` are PCRE control-verb patterns which modify the behaviour of the engine. Once a pattern is matched, `(*SKIP*)` tells the engine to "skip" to the next position once the first try of matching succeeded. Then `(*F)` - aka `(*FAIL)` - will tell the engine to act as if the matching failed, in order to retry pattern matching at the current position. More infos [here](http://stackoverflow.com/a/24535912/4375327). Official PERL doc [here](http://perldoc.perl.org/perlre.html). – Amessihel Oct 02 '15 at 12:06
  • Another interesting point : is here `preg_replace` more optimized than a couple of str_replace ? – Amessihel Oct 02 '15 at 12:08
0

Not using preg_replace, just to give you an idea, my code is not optimized ! (I know)

$str = 'xyzdsdasdas@xyss.com';
$buff = explode('@', $str);
$buff2 = explode('.', $buff[1]);

$part1 = $buff[0][0] . str_repeat('*', strlen($buff[0]) - 2) . $buff[0][strlen($buff[0]) - 1];
$part2 = $buff[1][0] . str_repeat('*', strlen($buff2[0]) - 2) . $buff2[0][strlen($buff2[0]) - 1];

echo $part1 .'@'. $part2 .'.'. $buff2[1];

But it works.

Vincent Decaux
  • 9,857
  • 6
  • 56
  • 84
0

Also you can use preg_replace_callback function

function callbackFunction($m) {
  return $m[1].(str_repeat('*', strlen($m[2]))).$m[3].(str_repeat('*', strlen($m[4]))).$m[5];
}

$pattern = '|^(\\w)(.*?)(.@.)(.*?)(.\\.\\w+)|';
$subject = 'xyzdsdasdas@xyss.com';
print_r( preg_replace_callback($pattern, 'callbackFunction', $subject, -1 ) );
Arsen
  • 10,815
  • 2
  • 34
  • 46
0

Another try, without explode :

<?php

$email="blablabla@truc.com" ;

$arobase_pos = strpos($email,"@"); // first occurence of "@"
$dot_pos = strrpos($email,".");    // last occurence of ".""

// from 2 to post(@) -1
$email = substr_replace($email, str_repeat ("*", $arobase_pos - 2), 1, $arobase_pos - 2);
// from pos(@)+2 to pos(.)-1 
$email = substr_replace($email, str_repeat ("*", $dot_pos-1-$arobase_pos-2),  $arobase_pos + 2, $dot_pos-1-$arobase_pos-2);

// Display
echo $email;
?>
Amessihel
  • 5,891
  • 3
  • 16
  • 40