Leetcode 831. Masking Personal Information

Problem Explanation

Given a string representing personal information (either an email or a phone number), we are asked to return a "masked" version of the personal information, to protect the sensitive data. The problem provides specific rules for masking both emails and phone numbers.

For an email, we need to turn it all in lowercase, retain the first and last letters of the first name and replace everything between the first and last letters of the first name with five '*'.

For a phone number, we need to keep only the last 4 digits from the local number, replace all other digits with '*', and add '-' for formatting, keeping in mind the country code is optional.

Solution Approach

For this problem, we will determine whether the input string is an email or a phone number and then apply the corresponding masking rules. This can be done efficiently using the built-in string and list methods provided by most programming languages.

A simple approach would be:

  1. To identify emails: If we find an '@' in our string, we lower case the string, separate the first character, add 5 '*' and concatenate it with the original string starting from (index_of'@'-1).

  2. To identify phone numbers: If there is no '@', we know it's a phone number. We then remove anything that's not a digit from our string. Now for the case of local numbers (10 digits) and international numbers (more than 10 digits), we create the necessary string format.

Python Solution

1
2python
3class Solution:  
4    def maskPII(self, s: str) -> str:  
5        if '@' in s:
6            first, after = s.split('@')
7            return "{}*****{}@{}".format(first[0], first[-1], after).lower()
8        
9        digits = [i for i in s if i.isdigit()]
10        local = "***-***-" + "".join(digits[-4:])
11        if len(digits) == 10:
12            return local
13        return "+" + "*" * (len(digits) - 10) + "-" + local

Java Solution

1
2java
3class Solution {
4    public String maskPII(String s) {
5        int atIndex = s.indexOf('@');
6        if (atIndex >= 0) {
7            s = s.toLowerCase();
8            return s.charAt(0) + "*****" + s.substring(atIndex - 1);
9        }
10        String digits = s.replaceAll("\\D+", "");
11        String local = "***-***-" + digits.substring(digits.length() - 4);
12        if (digits.length() == 10) return local;
13        String intl = '+' + String.join("", Collections.nCopies(digits.length() - 10, "*")) + '-';
14        return intl + local;
15    }
16}

JavaScript Solution

1
2javascript
3class Solution {
4    maskPII(S) {
5        if (S.indexOf('@') > -1) {
6            S = S.toLowerCase();
7            return S.charAt(0) + "*****" + S.slice(S.indexOf('@') - 1);
8        }
9        S = S.replace(/\D/g, '');
10        return (S.length > 10 ? '+' + '*'.repeat(S.length - 10) + '-' : '') + "***-***-" + S.slice(-4);
11    };
12};

C++ Solution

1
2cpp
3class Solution {
4public:
5    string maskPII(string s) {
6        int atIndex = s.find('@');
7        if (atIndex != std::string::npos) {
8            std::transform(s.begin(), s.end(), s.begin(), ::tolower);
9            return s.substr(0, 1) + "*****" + s.substr(atIndex - 1);
10        }
11        std::string res;
12        for(const char c : s) {
13            if(isdigit(c))
14                res += c;
15        }
16        if(res.length() == 10)
17            return "***-***-" + res.substr(res.length()-4);
18        return '+' + std::string(res.length()-10,'*') + "-***-***-" + res.substr(res.length()-4);
19    }
20};

C# Solution

1
2csharp
3public class Solution {
4    public string MaskPII(string S) {
5        int atIndex = S.IndexOf('@');
6        if (atIndex >= 0) {
7            S = S.ToLower();
8            return S[0] + "*****" + S.Substring(atIndex - 1);
9        }
10        string digits = string.Join("", S.Where(Char.IsDigit));
11        string local = "***-***-" + digits.Substring(digits.Length - 4);
12        if (digits.Length == 10) return local;
13        string intl = '+' + new String('*', digits.Length - 10) + '-';
14        return intl + local;
15    }
16}

Ruby Solution

1
2ruby
3class Solution
4    def mask_pii(s)
5        at_index = s.index('@')
6        if at_index != nil
7            s = s.downcase()
8            return s[0] + "*****" + s[at_index - 1, s.length]
9        end
10        digits = s.gsub(/[^0-9]/, '')
11        local = "***-***-" + digits[digits.length - 4, digits.length]
12        if digits.length == 10
13            return local
14        end
15        intl = '+' + '*' * (digits.length - 10) + '-'
16        return intl + local
17    end
18end

The Ruby solution applies the same steps: first, it checks if the string includes '@'. If so, it masks the email. If it doesn't include '@', it cleans the string to only include numbers and proceeds to mask the phone number. If the phone number includes a country code (more than 10 digits), it adds the appropriate number of asterisks.

Scala Solution

1
2scala
3class Solution { 
4  def maskPII(s: String): String = {
5    if (s.indexOf('@') >= 0) {
6      val lower = s.toLowerCase()
7      lower.head + "*****" + lower.substring(lower.indexOf('@') - 1)
8    } else {
9      val phoneDigits = s.filter(_.isDigit)
10      val local = "***-***-" + phoneDigits.takeRight(4)
11      if (phoneDigits.length > 10) "+" + "*" * (phoneDigits.length - 10) + "-" + local
12      else local
13    }
14  }
15}

The Scala solution uses the built-in indexOf method to locate the '@' character in the string. If '@' is found, we are dealing with an email, pass it to the lowercase and mask the necessary parts. If '@' is not found, we filter out all characters that are not digits and treat the result as a phone number, to mask the appropriate parts. If the phone number is more than 10 digits long, it must include a country code, which we account for in our return statement.

All these solutions demonstrate standard usage of string and list methods, with minor differences due to language-specific syntax. They handle both provided cases ('@' present or not) and accomplish the task effectively and efficiently.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫