My solution may not be the most effective, but as I have not seen many solutions commenting on some points I decided to write mine.
I created a regular expression that identifies whether a string is a phone, taking into account the following cases:
- 0800 Phones
- Carrier and service numbers like 10315 and 190
- Telephones represented with or without parentheses
- Accepts operator represented as 0xx11
- Phones with or without tabs [.-]
- Ignore phones starting with 0 if you do not have DDD (ex: 0999-9999 is not accepted, but 0xx11 is 9123-1234)
It got a little big and hard to read humanly, but it suits my projects:
/^1\d\d(\d\d)?$|^0800 ?\d{3} ?\d{4}$|^(\(0?([1-9a-zA-Z][0-9a-zA-Z])?[1-9]\d\) ?|0?([1-9a-zA-Z][0-9a-zA-Z])?[1-9]\d[ .-]?)?(9|9[ .-])?[2-9]\d{3}[ .-]?\d{4}$/gm
You can see the expression
After validating if the expression is a phone, you can format it any way you think best by manipulating the string.
Here is an example in Java (where PHONE_MATCH is the regular expression):
public String phone(String phoneString) throws IllegalArgumentException {
if (!phoneString.matches(PHONE_MATCH)) {
throw new IllegalArgumentException("Not a valid phone format");
}
String str = phoneString.replaceAll("[^\d]", "");
if (str.charAt(0) == '0') {
if (str.charAt(1) == '0') {
str = str.substring(2);
} else {
str = str.substring(1);
}
}
switch (str.length()) {
case 8:
return applyMask(str, "AAAA-AAAA", 'A');
case 9:
return applyMask(str, "AAAAA-AAAA", 'A');
case 10:
return applyMask(str, "(AA) AAAA-AAAA", 'A');
case 11:
return applyMask(str, "(AA) AAAAA-AAAA", 'A');
default:
return str;
}
}
ApplyMask method:
public String applyMask(String str, String mask, char specialChar) {
// Conta quantos caracteres especiais existem na máscara
int maskChCount = mask.length() - mask.replaceAll("[^" + specialChar + "]", "").length();
// Conta apenas os números
int strChCount = str.length() - str.replaceAll("\d", "").length();
// Exceção caso a string nao tenha números suficientes para competar a máscara
if (strChCount < maskChCount) {
throw new IllegalArgumentException("The number of chars in the string should not be smaller than the " +
"number of special chars in the mask");
}
char[] maskChars = mask.toCharArray();
char[] strChars = str.toCharArray();
// Itera por todos os elementos da máscara
for (int i = 0, j = 0; i < maskChars.length && j < strChars.length; i++) {
char ch = maskChars[i];
char sh = strChars[j];
if (ch == specialChar) {
// Se achou o caractere especial, buscar o próximo elemento aceito da String e
// substituí-lo no local do caractere especial
while (!Character.toString(sh).matches("\d")) {
j++;
sh = strChars[j];
}
maskChars[i] = sh;
j++;
}
}
return new String(maskChars);
}
I think you have several ways to optimize this code, any suggestions are welcome.