## DEV Community is a community of 753,853 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

# Daily Challenge #179 - Hide Phone Numbers

### Setup

Implement a function that will hide the last six digits of each phone number. Your function should be able to understand the separators for US numbers. Phone numbers can be separated by spaces, periods, or hyphens.

### Examples

Original: `201-680-0202`
Encrypted: `201-6XX-XXXX

### Tests

encryptNum("328 6587120")
encryptNum("212-420-0202")
encryptNum("211-458-7851")

This challenge comes from otrebor6 on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

## Discussion (21) Aldwin Vlasblom • Edited on

JavaScript:

``````const encryptNum = num => num.replace(/(\d[ .-]?){6}\$/, x => x.replace(/\d/g, 'X'))
``````

The first `replace` finds the last 6 digits, with or without trailing separators.
The resulting match undergoes another `replace` call to substitute any digits for X's.

The first expression can also be relaxed to allow any separators: `/(\d[^\d]?){6}\$/`, or even any number of separators: `/(\d[^\d]*){6}\$/`. Edvinas Pranka

Javascript

``````function encryptNum(num){
return num.substr(0, 5) + 'XX-XXXX'
}
`````` George WL • Edited on

True, but it does expect the tests to all pass still, which they won't with that solution Nice short solution!

If I'm being correct, for the string `"328 6587120"`, the expected output should be `"328 6XXXXXX"`.

But in your case, the output would be `"328 6XX-XXXX"`. Idan Arye

Rust:

``````fn encrypt_num(phone_number: String) -> String {
let mut bytes = phone_number.into_bytes();
for ch in bytes.iter_mut().rev().filter(|b| {
let c = **b as char;
'0' <= c && c <= '9'
}).take(6) {
*ch = 'X' as u8;
}
String::from_utf8(bytes).unwrap()
}

fn main() {
assert_eq!(encrypt_num("328 6587120".to_owned()), "328 6XXXXXX");
assert_eq!(encrypt_num("212-420-0202".to_owned()), "212-4XX-XXXX");
assert_eq!(encrypt_num("211-458-7851".to_owned()), "211-4XX-XXXX");
}
`````` Elm

``````encryptDigit : Char -> Char
encryptDigit character =
if Char.isDigit character then
'X'

else
character

encryptNum : String -> String
encryptNum string =
String.map encryptDigit ( String.dropLeft 5 string )
|> String.append ( String.left 5 string )
`````` Alvaro Montoro

JavaScript

If we want all the phone numbers to have the same format, we could use a regular expression to detect all the digits (assuming that the phone number is correct) and format it accordingly:

``````const encryptNum = (num) => {
const nums = num.match(/\d/gi).join("");
return `\${nums.substring(0,3)}-\${nums.substring(3,6)}-\${nums.substring(6)}`;
}
``````

If we want to keep the original format (and again, assuming the phone number is correct), another solution would be transforming the string into an array (strings are immutable, an array would be easier to operate), parse the last 6 digits and return its concatenation:

``````const encryptNum = (num) => {
let numbers = 0;
let position = num.length - 1;
let formattedNum = num.split("");

while (numbers < 6 && position > 0) {
if (num[position] >= "0" && num[position] <= "9") {
formattedNum[position] = "x";
numbers++;
}
position--;
}

return formattedNum.join("");
}
`````` Valts Liepiņš

Haskell, similar idea to my solution in Ruby

``````import Data.Char (isDigit)

encryptNum :: String -> String
encryptNum = reverse . encryptDigit 0 . reverse
where
encryptDigit 6 xs     = xs
encryptDigit i (x:xs) | isDigit x = 'X' : encryptDigit (i+1) xs
| otherwise =  x  : encryptDigit i xs
`````` zoe-j-m

Scala,

``````def encryptNum(input : String) = {
def encryptInner(remain : Int, toGo : List[Char]) : List[Char] = {
toGo match {
case Nil => Nil
case _ if remain == 0 => toGo
case x::xs if x.isDigit => 'X' :: encryptInner(remain - 1, xs)
case x::xs => x :: encryptInner(remain, xs)
}
}

encryptInner(6, input.reverse.toList).reverse.mkString
}
`````` lusen / they / them 🏳️‍🌈🥑

Python, a straightforward approach that would be fast to design and implement without bugs during an interview. It is big-O optimal and easy to understand and refactor.

``````def encrypt(phone_num):
# define some const. easy to refactor into method sig or config elsewhere later
ENCRYPT_NUMBER = 6
ENCRYPT_SYMBOL = 'X'

# we'll return this at the end - reversed and joined.
encrypted = []
# count the numbers we encrypt
counter = 0

# start at the end and encrypt numbers until we reach ENCRYPT_NUMBER
for ch in phone_num[::-1]:
# we're done encrypting so pass everything along
if counter == ENCRYPT_NUMBER:
encrypted.append(ch)
continue

try:
# if character is a number, encrypt it
int(ch)
counter += 1
encrypted.append(ENCRYPT_SYMBOL)
except ValueError:
# character is not a number so pass it  through
encrypted.append(ch)

# return a string in the right order
return ''.join(encrypted[::-1])

print(encrypt("328 6587120")) # 328 6XXXXXX
print(encrypt("212-420-0202")) # 212-4XX-XXXX
print(encrypt("211-458-7851")) # 211-4XX-XXXX
print(encrypt("211 458 7851")) # 211 4XX XXXX
print(encrypt("2114587851")) # 2114XXXXXX
`````` Matt Ellen • Edited on

ONE REGEX TO RULE THEM

Put your separators where you want! I'll find them all.

``````const encryptNum = num => num.replace(/((\d[-\s.]?){4})(\d)([\s.-]?)(\d)([\s.-]?)(\d)([\s.-]?)(\d)([\s.-]?)(\d)([\s.-]?)(\d)/, '\$1X\$4X\$6X\$8X\$10X\$12X');
`````` Dart - not a fan of being creative.

``````String encryptNum(String phoneNum) {
var regexp = RegExp(r"([0-9- .]+)");
var result = regexp?.firstMatch(phoneNum)?.group(0);
result = result?.replaceAll(new RegExp(r"(\.|-|\s)"), "");
if(result.length == 10) {
var val = StringBuffer();
for(var idx = 0; idx < result.length; idx++) {
if(idx < 4) {
val.write(result[idx]);
} else {
val.write("X");
}
switch(idx) {
case 2:
case 5:
val.write("-");
break;
}
}
return val.toString();
}
return null;
}
``````
``````print(encryptNum("142 424 2142"));
print(encryptNum("142 424-2142"));
print(encryptNum("142 424.2142"));
print(encryptNum("142 4242142"));
print(encryptNum("142-424-2142"));
print(encryptNum("142-424 2142"));
print(encryptNum("142-424.2142"));
print(encryptNum("142-4242142"));
print(encryptNum("142.424 2142"));
print(encryptNum("142.424-2142"));
print(encryptNum("142.424.2142"));
print(encryptNum("142.4242142"));
print(encryptNum("142424-2142"));
print(encryptNum("142424.2142"));
print(encryptNum("142424 2142"));
print(encryptNum("1424242142"));
`````` George WL • Edited on

Didn't even know you can embed into comments, that's really cool.

Do you not feel that solution is overcomplicating it?