How to make a regular expression for mobile phone?

Asked

Viewed 69,449 times

29

How to create a regular expression to validate the phone field you accept 99-99999999 (DDD + 8 numbers) or 99-999999999 (DDD + 9 numbers). And that when typing it add the dash - automatically!

ValidationExpression="^[0-9]{2}-([0-9]{8}|[0-9]{9})"

How to proceed?

5 answers

74

Nowadays all mobile phones in Brazil have nine digits and start with digit 9 and all fixed phones have 8 digits and never start with digit 9. I would personally prefer to format the phone as (xx) xxxxx-xxxx. So the best regular expression for this would be this:

^\([1-9]{2}\) (?:[2-8]|9[1-9])[0-9]{3}\-[0-9]{4}$

Her full explanation is:

  • ^ - String start.
  • \( - One parentheses.
  • [1-9]{2} - Two digits from 1 to 9. No DDD codes with digit 0.
  • \) - A close parenthesis.
  • - A blank space.
  • (?:[2-8]|9[1-9]) - The beginning of the number. Represents a choice between the one digit between 2 and 8 (the part of [2-8]) and a 9 followed by a digit from 1 to 9 (the part of the 9[1-9]). The | separates the options to be chosen. O (?: ... ) groups such choices. Fixed phones start with digits from 2 to 8. Mobile phones start with 9 and have a second digit from 1 to 9. The first digit will never be 0 or 1. Mobile phones can’t start with 90 because this is the prefix for collect calls.
  • [0-9]{3} - The remaining three digits of the first half of the phone number, making a total of 4 or 5 digits in the first half.
  • \- - A hyphen.
  • [0-9]{4} - The second half of the phone number.
  • $ - String end.

If you want to leave the parentheses, blank space and hyphen optional, then you can put a ? after each of these symbols, resulting in this regular expression:

^\(?[1-9]{2}\)? ?(?:[2-8]|9[1-9])[0-9]{3}\-?[0-9]{4}$

If you want, you can also filter the Ddds that exist. Here’s an image that shows the current area codes according to the Wikipedia:

Mapa do Brasil com as divisões por DDD

Looking at this map, the subexpression that would filter the valid Ddds would be as follows:

(?:[14689][1-9]|2[12478]|3[1234578]|5[1345]|7[134579])

As explained above, the (?: ... ) is to group. The options (separated by |) would be two-digit groups, which would be one of the following options: 2[12478] to Rio de Janeiro and Espírito Santo, 3[1234578] to Minas Gerais, 5[1345] to Rio Grande do Sul, 7[134579] to Bahia and Sergipe and [14689][1-9] for the rest of Brazil.

And the complete regular expression would be as follows (with the mandatory parentheses, spaces and hyphens):

^\((?:[14689][1-9]|2[12478]|3[1234578]|5[1345]|7[134579])\) (?:[2-8]|9[1-9])[0-9]{3}\-[0-9]{4}$

And with them not obligatory:

^\(?(?:[14689][1-9]|2[12478]|3[1234578]|5[1345]|7[134579])\)? ?(?:[2-8]|9[1-9])[0-9]{3}\-?[0-9]{4}$

NOTE: This answer was originally written in 2015, when there were 8 or 9 digit cell phones, depending on the area code. Since then, it has been upgraded to the newest format in effect, which always has 9 digits. If you want more details on how this response was edited, check out the edition history.

  • what does this escape mean \ before space? Here ...^\([1-9]{2}\)\ [2-9]... I don’t think it’s necessary to escape a space :)

  • @Guilhermenascimento Really. I do not remember why I had put the bar before, since it has been a few months. I think I must have got into trouble with something at the time of building the regex.

  • 1

    Victor is normal, I do it all the time, Jorgeb. He’s always following my spelling mistakes :)

  • 3

    @Victorstafusa, you deserve a prize for the beautiful explanation. Rather than much tutorial from regex blogs out...

  • I use a \s to escape the space. That’s because I’m wearing a mask in the field and I’m sure it will always come this space.

  • @Victorstafusa thank you!

Show 1 more comment

9

My solution may not be the most effective, but as I did not see many solutions commenting on some points I decided to write my.

I created a regular expression that identifies whether a string is a phone, taking into account the following cases:

  • Telephones 0800
  • Operator numbers and services like 10315 and 190
  • Telephones represented with or without parentheses
  • Accepts carrier 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 9123-1234 is)

It got a little big and difficult to read humanly, but it attends 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 in use at this link.

After validating whether the expression is a phone, you can format it the 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 believe you have several ways to optimize this code, any suggestion is welcome.

  • 1

    I didn’t use your answer, but thank you very much for the website you did your example. http://regexr.com

5

I use this

@"^\(?\d{2}\)?[\s-]?[\s9]?\d{4}-?\d{4}$"

If you put 9 digits it forces you that the first digit is 9.

I would take a little of each example to assemble the ideal.

  • 1

    Gabriel Santos Reis, your mask is perfect guy. Congratulations!

2

Guys, with your help I created a string that I thought was ideal for me. Simple and direct. In WHMCS use to start and close /. I will not use in the example to follow your example. Come on. The expression looks like this:

^\([1-9]{2}\) [9]{0,1}[6-9]{1}[0-9]{3}\-[0-9]{4}$

Explanation:

  • ^ = String start.
  • \( = One parentheses.
  • [1-9]{2} = Two digits from 1 to 9. No DDD codes with digit 0.
  • \) = A close parenthesis.
  • = A blank space.
  • [9]{0,1} = The first digit is 9, plus it may or may not exist hence the "0" or "1" within the {0.1}.
  • [6-9]{1} = the second digit can be 6 to 9.
  • [0-9]{3} = The three other digits are 0 to 9
  • \- = A hyphen.
  • [0-9]{4} = The second half of the phone number.
  • $ = String end.

Remembering friends that at WHMCS should start and close with /. By the end of 2016 or more precise in November 6, 2016 all Brazil will have the 9 at the beginning of cell phones.

  • 1

    My phone starts with 95. Your rule of "the second digit can be 6 to 9" would bar my cell phone.

  • @Victorstafusa is just changing to ^\([1-9]{2}\) [9]{0,1}[5-9]{1}[0-9]{3}\-[0-9]{4}$&#xA; where you’re from and which operator is yours to start with 95?

  • @Leocavalcante I’m from São Paulo and I use TIM, but with portability, the operator doesn’t matter. DDD 11 has the largest number of lines registered. As I remember, according to Anatel, the rule is that all 9 digit phone numbers starting with 9 are cell phones, and start counting from the number 99999-9999 back-to-front to the 91000-0000, which is when the number of lines available in the DDD would be exhausted. And if I’m not mistaken, we already have the first numbers starting with 94 in Area Code 11. I have another answer here in this question that avoids these limitations.

  • @Leocavalcante Actually, I already have a number on my contact list starting with 93 on Area Code 11.

1

^\([1-9]{2}\) 9[7-9]{1}[0-9]{3}\-[0-9]{4}$
  • [1-9]{2} = Two digits from 1 to 9. No DDD with digit 0.
  • 9 = All cell phones from 2016 start by 9
  • [7-9]{1} = In the old numbering the phones started with 7, 8 or 9
  • [0-9]{3} = The three other digits can be from 0 to 9
  • [0-9]{4} = The four after the hyphen can be 0 to 9
  • My phone starts with 95. It is rejected by its regex.

  • 1

    Thanks to the ninth digit, we can now have phones that start with 96, 95, 94, etc. So use [7-9] rejects valid numbers, as @Victorstafusa rightly pointed out. Another detail is that {1} is unnecessary because (qualquer coisa){1} is the same as (qualquer coisa)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.