11

I am trying to write a regular expression to mask an email address. Example below.

input: john.doe@example.en.com

output: j*******@e*********.com

I have tried the following but I just can't seem to get it working correctly.

regex:(?<=.).(?=[^@]\*?@)

output:j*******@example.en.com

regex:(?<=.).(?=[^@]\*?)(?=[^\.]\*?\.)

output:j******************.com

Any help would be appreciated. demo

Community
  • 1
  • 1
Randall Kwiatkowski
  • 895
  • 2
  • 12
  • 23
  • 1
    Try [`.replaceAll("(?<=.).(?=[^@]*?@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$))(.)(?=.*\\.)", "*")`](https://regex101.com/r/Bwsy9X/1) (beware of garbage chars in this comment, do not copy/paste from here) – Wiktor Stribiżew Mar 24 '17 at 15:19
  • 2
    How important is the use of regular expressions to you? IMHO `.indexOf("@")` and some "substring-copy-paste" might be more readable in a couple of months. – DerMike Mar 24 '17 at 15:27
  • @DerMike It's not important. I just got it stuck in my head that I needed to use a regex. – Randall Kwiatkowski Mar 24 '17 at 15:35
  • @Wiktor That regex works. If you submit it as an answer I will accept it. Thanks! – Randall Kwiatkowski Mar 24 '17 at 15:35

2 Answers2

36

Update with various masking email solutions

  • foo@bar.comf**@b**.com (current question) - s.replaceAll("(?<=.)[^@](?=[^@]*?@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?=.*\\.)", "*") (see the regex demo)

  • foo@bar.comf**@b*r.com - s.replaceAll("(?<=.)[^@](?=[^@]*?@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?=.*[^@]\\.)", "*") (see the regex demo)

  • foo@bar.comf*o@b*r.com - s.replaceAll("(?<=.)[^@](?=[^@]*?[^@]@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?=.*[^@]\\.)", "*") (see the regex demo)

  • foo@bar.comf**@b*****m - s.replaceAll("(?<=.)[^@](?=[^@]*?@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?!$)", "*") (see the regex demo)

  • foo@bar.comf*o@b*****m - s.replaceAll("(?<=.)[^@](?=[^@]*[^@]@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?!$)", "*") (see the regex demo)

Original answer

In case you can't use a code-based solution, you may use

s.replaceAll("(?<=.)[^@](?=[^@]*?@)|(?:(?<=@.)|(?!^)\\G(?=[^@]*$)).(?=.*\\.)", "*")

See the regex demo

What it does:

  • (?<=.)[^@](?=[^@]*?@) -any char other than @ ([^@]) that is preceded by any single char ((?<=.)) and is followed with any 0 or more chars other than @ up to a @ ((?=[^@]*?@))
  • | - or
  • (?:(?<=@.)|(?!^)\\G(?=[^@]*$)) - match a location in the string that is preceded with @ and any char ((?<=@.)) or (|) the end of the previous successful match ((?!^)\\G) that is followed with any 0+ chars other than @ uo to the end of string ((?=[^@]*$))
  • . - any single char
  • (?=.*\\.) - followed with any 0+ chars up to the last . symbol in the string.
Community
  • 1
  • 1
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Wouldn't `\S+@\S+` do as well, for most email addresses? – Robert Mar 24 '17 at 16:32
  • @Robert: I do not believe you can use it for masking. You can use it for extracting most of emails. – Wiktor Stribiżew Mar 24 '17 at 16:54
  • @WiktorStribiżew, any example where we can do f@b.com to `*@*.**m` – kakabali Aug 18 '19 at 08:43
  • @kakabali `s.replaceAll("[^@.](?!$)", "*")` – Wiktor Stribiżew Aug 18 '19 at 19:52
  • What can I do to get f\*o@b\*r.com.br ? I need the domain to be full visible – user2494863 Sep 30 '20 at 16:33
  • 1
    @user2494863 If you want to mask the domain part before the first dot, use `(?<=.)[^@\n](?=[^@\n]*?[^@\n]@)|(?:(?<=@.)|(?!^)\G(?=[^@\n]*$))[^.](?!\.)`, see [demo](https://regex101.com/r/Bwsy9X/106). – Wiktor Stribiżew Sep 30 '20 at 19:34
  • @WiktorStribiżew besides the RegEx you proposed in the last comment, would it be possible to do the same replacement, but masking the e-mail in a larger string like a JSON for example? `{"name": "john.doe@example.en.com"} => {"name": "j***e@e***e.com"}` – Pavel Razgovorov Oct 26 '20 at 15:27
  • @PavelRazgovorov Parse JSON first, it is not plain text. Use regex only on plain text. – Wiktor Stribiżew Oct 26 '20 at 15:28
  • @WiktorStribiżew Right now I'm extracting the email with a first RegEx and then replacing it with one of yours as a (repeated) second step. The string does not have to be a JSON, it could be any string: `"Send me an e-mail to john.doe@example.en.com" => "Send me an e-mail to j***e@e***e.en.com"` – Pavel Razgovorov Oct 26 '20 at 15:45
  • does not work with short email addresses such as gp@m3.ru =( – Ivan Smorodin Jul 19 '21 at 10:25
  • @IvanSmorodin It depends what you need. [This works](https://regex101.com/r/Bwsy9X/151)., and [this works, too](https://regex101.com/r/Bwsy9X/152), also, see [this demo](https://regex101.com/r/Bwsy9X/153). – Wiktor Stribiżew Jul 19 '21 at 10:33
4

How about this one if you do not need the masks having the same number of characters of the original strings (which is more anonymous):

(?<=^.)[^@]*|(?<=@.).*(?=\.[^.]+$)

For example, if you replace the matches with ***, the result would be:

j***@e***.com
Chuancong Gao
  • 654
  • 5
  • 7