How to differentiate phone types

Asked

Viewed 30,495 times

22

I have the following problem: the customer will send me a phone number and I need to differentiate whether it is fixed or mobile, someone knows some rules that distinguish well the two groups?

7 answers

35


The Numbering Plan is the way in which the numbers of telecommunications services for public use are organised. The table below has the relationship between the numeric ranges of landline and mobile phone, based on this I think it is easy to solve your problem.

inserir a descrição da imagem aqui

Source: Teleco

28

Structure of the Brazilian Telephone System

Numbers can essentially have 4 portions:

In addition, there are other numbers with a special nomenclature, the public utility numbers containing only 3 digits.

Types of numbers

There are only two types of numbers, fixed or mobile, distinguished by the first digit:

  • 2 to 5 are fixed numbers (land line)
  • 6 to 9 are mobile numbers (mobile phone)

Pseudocode

Based on the above data, the algorithm would have to work within the following templates:

  1. Check if it has more than three digits to determine if it is a public utility number.

    If it’s public utility, we finish here and act accordingly.

  2. Check if number starts with +55 to determine if you have the country call code.

    If you have the country call code, we will remove it from the number and continue with the check.

  3. Check if it has at least 12 digits.

    If it doesn’t have 12 or more digits, it’s invalid, we end up here and act accordingly.

  4. Check if it has 13 digits.

    If it has 13 digits, it is São Paulo’s mobile number, we finish here and act accordingly.

  5. Determine whether fixed or mobile.

    Getting here we have to have 12 digits, so let’s take the 5th digit and check if it is in the group (2~5) or in the group (6~9), finish the operation and act accordingly.

  6. Optional:

    Break the 12 digits into portions to identify where it is:

    2 dígitos - Operadora
    2 dígitos - Área geográfica
    4 dígitos - Primeira parte do número
    4 dígitos - Segunda parte do número
    

Diagram

The flow of information based on what we have calculated so far can be presented as follows::

Diagrama - Fluxo de informação

Code

Putting this whole exercise into practice, we will implement the solution with Javascript:

document.getElementById("validar").onclick = function() {

  var continuar = true,
    numero = document.getElementById('numero').value;

  // Verificar se vazio
  if (numero.length === 0) {
    alert("Brincalhão, preenche lá o número!");
    continuar = false;
  }

  // Verificar se número é de utilidade publica
  if (numero.length === 3) {
    alert("Número de utilidade publica");
    continuar = false;
  }

  // Verificar se tem código do país para retirar
  if (continuar && numero.substring(0, 3) === "+55") {
    numero = numero.substring(3);
  }

  // Verificar se menos que 12 digitos
  if (continuar && numero.length < 12) {
    alert("Número inválido, por favor introduza Cod. Operadora + Cod. Area + Numero");
    continuar = false;
  }

  // Verificar se contém 13 digitos
  if (continuar && numero.length === 13) {
    alert("Número móvel");
    continuar = false;
  }

  // Verificar se o 5º digito
  var digitoControlo = numero.charAt(4);

  if (continuar) {

    if (digitoControlo >= 2 && digitoControlo <= 5) {
      alert("Número fixo");
    } else if (digitoControlo >= 6 && digitoControlo <= 9) {
      alert("Número móvel");
    } else {
      alert("Número especial");
    }
  }
}
<form>
  <input type="text" id="numero" name="numero" />
  <button id="validar">validar</button>
</form>

Notes:

There are other checks to be carried out, such as where there are no letters in place of numbers, but such checks are not part of the establishment of the number and should be taken into account before the number is started.

Some of the checks may not even be required, it goes from the implementation of each one, reason why they are separate, becoming modular.


I am Portuguese from Portugal, if I missed some detail on the structure of the "your" telephone system, leave a comment, I will be happy to update the answer.

  • 1

    Great answer, I just missed a more direct reference to corroborate his statement that "If it has 13 digits, it is São Paulo’s mobile number, we finish here and act accordingly." (after all, this was the motivation of the reward...) I say "more direct," because that information is half-hidden in the Wikipedia article to which your reply links. But it is there, accompanied by citations, so that I consider the reference valid. + 1 and reward granted!

  • @mgibsonbr I have a review for the example code in the question, I will take the opportunity to be more transparent in the issue of São Paulo when making the edition!

5

  • according to the comment I made in the question, I know how to use regex, this is not the problem, I need an "algorithm" or a rule that I can separate the two groups.

3

You can use the new Twillo Lookup service.

https://www.twilio.com/lookup

With the paid module he gives you the type of the number (mobile or fixed) and also the operator.

curl -X GET https://lookups.twilio.com/v1/PhoneNumbers/55-11-5525-6325\
    -d "Type=carrier"
    -u "{AccountSid}:{AuthToken}"

{
    "country_code": "BR",
    "phone_number": "+551155256325",
    "national_format": "(11) 5525-6325",
    "url": "https://lookups.twilio.com/v1/PhoneNumber/+551155256325",
    "carrier": {
        "type": "landline",
        "error_code": null,
        "mobile_network_code": null,
        "mobile_country_code": null,
        "name": "Vivo"
    }
}

3

After studying the response of Zuul and analyse this article from Anatel, I adapted his solution (in Javascript) for the two main programming languages I use: Java and Object Pascal. Creating the respective classes. And the code has been tested and is working for numbers with and without the NINTH DIGIT.

However, I made some changes to accept special numbers, such as 0300, 0500, 0800, 0900, 3003, 4003 and 4004. I also fixed some bugs when the user reports numbers with extra zeros, for example: (OP) 041 (DDD) 87 (NUM) 9999-9999, or: (OP) 41 (DDD) 087 (NUM) 9999-9999.

Below the code of the classes.

In Java:

/*
        Telefone - Retorna o tipo de um número de telefone (fixo, móvel, público etc.)

        Baseado neste tópico:

        . /questions/14343/como-diferenciar-tipos-de-telefone

        Autores:

        . Silvio Clécio - github.com/silvioprog
*/

package br.com.duallsistemas.telefone;

/**
 * Created by silvioprog on 06/04/2015.
 */
public class Telefone {
    private String numero;
    private String ddd;
    private String codOperadora;

    public Telefone(String codOperadora, String ddd, String numero) {
        this.codOperadora = apenasNumeros(apenasString(codOperadora));
        this.ddd = apenasNumeros(apenasString(ddd));
        setNumero(numero);
    }

    public Telefone(String codOperadora, String ddd) {
        this(codOperadora, ddd, "");
    }

    public Telefone() {
        this("", "");
    }

    private boolean inRange(int num, int min, int max) {
        return num >= min && num <= max;
    }

    private boolean numeroEspecial() {
        return numero.startsWith("0300") || numero.startsWith("0500") || numero.startsWith("0800") ||
                numero.startsWith("0900") || numero.startsWith("3003") || numero.startsWith("4003") ||
                numero.startsWith("4004");
    }

    private boolean temNonoDigito() {
        Integer i = Integer.parseInt(numero.substring(0, 2));
        return inRange(i, 11, 19) || inRange(i, 21, 24) || i == 27 || i == 28 || inRange(i, 91, 99);
    }

    protected String apenasNumeros(String s) {
        if (s == null)
            return "";
        String result = "";
        for (char c : s.toCharArray()) {
            if (c >= '0' && c <= '9')
                result += c;
        }
        return result;
    }

    protected String apenasString(String s) {
        if (s == null)
            return "";
        s = s.trim();
        if (s.equals(""))
            return "";
        return s;
    }

    public String getCodOperadora() {
        return codOperadora;
    }

    public String getDdd() {
        return ddd;
    }

    public TipoTelefone obtemTipo() {
        int len = numero.length();
        if (len <= 2)
            return TipoTelefone.INVALIDO;
        if (len == 3)
            return TipoTelefone.PUBLICO;
        if (len < 12) {
            if (numeroEspecial())
                return TipoTelefone.ESPECIAL;
            else
                return TipoTelefone.INVALIDO;
        }
        if (len == 13)
            return TipoTelefone.MOVEL;
        char digito;
        if (len == 15)
            digito = numero.charAt(7);
        else
            digito = numero.charAt(4);
        if (digito >= '2' && digito <= '5')
            return TipoTelefone.FIXO;
        if (digito >= '6' && digito <= '9')
            return TipoTelefone.MOVEL;
        return TipoTelefone.ESPECIAL;
    }

    public String getDescricao() {
        return String.valueOf(obtemTipo());
    }

    public String getNumero() {
        return numero;
    }

    public void setNumero(String numero) {
        numero = apenasString(numero);
        if (numero.equals(""))
            return;
        if (numero.startsWith("+55"))
            numero = numero.substring(3);
        this.numero = apenasNumeros(numero);
        int len = this.numero.length();
        if (len == 8 ) {
            if (!numeroEspecial())
                this.numero = codOperadora + ddd + this.numero;
        } else if (len == 9)
            this.numero = codOperadora + ddd + this.numero;
        else if (len == 10)
            this.numero = codOperadora + this.numero;
        else if (len == 11 || len == 14) {
            if (!numeroEspecial() && this.numero.substring(0, 1).equals("0")) {
                this.numero = this.numero.substring(1);
                this.numero = codOperadora + this.numero;
            } else if (temNonoDigito())
                this.numero = codOperadora + this.numero;
        }
    }
}

Example of use (Note: the numbers used in the example are fictitious):

package br.com.duallsistemas;

import br.com.duallsistemas.telefone.Telefone;

public class Main {

    public static void imprime(Telefone tel, String numero) {
        tel.setNumero(numero);
        System.out.println("NUMERO REAL: " + tel.getNumero() + ", TIPO: " + tel.getDescricao());
    }

    public static void main(String[] args) {
        Telefone tel = new Telefone("41", "65");
        System.out.println("INTRODUZA O NUMERO DO SEGUINTE FORMATO: COD. OPERADORA + COD. AREA + NUMERO");
        System.out.println("=======");
        System.out.println();
        // inválidos
        imprime(tel, "12");
        imprime(tel, "+55 41 (99) 999-9999");
        System.out.println();
        // público
        imprime(tel, "190");
        System.out.println();
        // especial
        imprime(tel, "0300 313 4701");
        imprime(tel, "0500 313 4701");
        imprime(tel, "0800 729 0722");
        imprime(tel, "0900 313 4701");
        imprime(tel, "3003 3030");
        imprime(tel, "4003 3030");
        imprime(tel, "4004 3030");
        System.out.println();
        // fixo
        imprime(tel, "3549-5589");
        imprime(tel, "(87) 3549-5589");
        System.out.println();
        // movel
        imprime(tel, "9985-0997");
        imprime(tel, "(87) 9985-0997");
        imprime(tel, "31 (87) 9985-0997");
        imprime(tel, "+55 31 (87) 9985-0997");
        System.out.println();
        // movel SP
        imprime(tel, "9 9985-0997");
        imprime(tel, "(11) 9 9985-0997");
        imprime(tel, "31 (11) 9 9985-0997");
        imprime(tel, "031 (11) 9 9985-0997");
    }
}

In Object Pascal (compatible with Free Pascal 2.6.4+ and Delphi 7+):

(*

  TTelefone - Retorna o tipo de um número de telefone (fixo, móvel, público etc.)

  Baseado neste tópico:

    . /questions/14343/como-diferenciar-tipos-de-telefone

  Autores:

    . Silvio Clécio - github.com/silvioprog

*)

unit Telefone;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}

interface

uses
  SysUtils;

type

  { TTipoTelefone }

  TTipoTelefone = (ttInvalido, ttPublico, ttFixo, ttMovel, ttEspecial);

  { TTelefone }

  TTelefone = class(TObject)
  private
    FNumero: string;
    FDdd: string;
    FCodOperadora: string;
    function GetCodOperadora: string;
    function GetDdd: string;
    function GetDescricao: string;
    function GetTipo: TTipoTelefone;
    procedure SetNumero(ANumero: string);
    function TemNonoDigito: Boolean;
    function NumeroEspecial: Boolean;
  public
    constructor Create(const ACodOperadora, ADdd, ANumero: string); overload; virtual;
    constructor Create(const ACodOperadora, ADdd: string); overload; virtual;
    constructor Create; overload; virtual;
    function ApenasNumeros(const S: string): string;
    function ApenasString(const S: string): string;
    property CodOperadora: string read GetCodOperadora;
    property Ddd: string read GetDdd;
    property Numero: string read FNumero write SetNumero;
    property Descricao: string read GetDescricao;
    property Tipo: TTipoTelefone read GetTipo;
  end;

const
  DESC_TELEFONE: array[TTipoTelefone] of string = (
    'INVALIDO', 'PUBLICO', 'FIXO', 'MOVEL', 'ESPECIAL'
    );

implementation

{ TTelefone }

constructor TTelefone.Create(const ACodOperadora, ADdd, ANumero: string);
begin
  inherited Create;
  FCodOperadora := ApenasNumeros(ApenasString(ACodOperadora));
  FDdd := ApenasNumeros(ApenasString(ADdd));
  SetNumero(ANumero);
end;

constructor TTelefone.Create(const ACodOperadora, ADdd: string);
begin
  Create(ACodOperadora, ADdd, '');
end;

constructor TTelefone.Create;
begin
  Create('', '');
end;

function TTelefone.TemNonoDigito: Boolean;
var
  I, E: Integer;
begin
  Val(Copy(FNumero, 1, 2), I, E);
  Result := E = 0;
  if Result then
    case I of
      11..19, 21..24, 27, 28, 91..99: Result := True;
      else
        Result := False;
    end;
end;

function TTelefone.NumeroEspecial: Boolean;
var
  N: ShortString;
begin
  N := Copy(FNumero, 1, 4);
  Result := (N = '0300') or (N = '0500') or (N = '0800') or (N = '0900') or
    (N = '3003') or (N = '4003') or (N = '4004');
end;

function TTelefone.ApenasNumeros(const S: string): string;
var
  C: Char;
{$IFNDEF FPC}
  I: Integer;
{$ENDIF}
begin
  Result := '';
{$IFDEF FPC}
  for C in S do
    if (C >= '0') and (C <= '9') then
      Result += C;
{$ELSE}
  for I := 1 to Length(S) do
  begin
    C := S[I];
    if (C >= '0') and (C <= '9') then
      Result := Result + C;
  end;
{$ENDIF}
end;

function TTelefone.ApenasString(const S: string): string;
begin
  Result := Trim(S);
end;

function TTelefone.GetCodOperadora: string;
begin
  Result := FCodOperadora;
end;

function TTelefone.GetDdd: string;
begin
  Result := FDdd;
end;

function TTelefone.GetTipo: TTipoTelefone;
var
  D: Byte;
  L
{$IFNDEF FPC}
  , E
{$ENDIF}
  : Integer;
begin
  L := Length(FNumero);
{$IFDEF FPC}
  if L <= 2 then
    Exit(ttInvalido);
  if L = 3 then
    Exit(ttPublico);
  if L < 12 then
  begin
    if NumeroEspecial then
      Exit(ttEspecial)
    else
      Exit(ttInvalido);
  end;
  if L = 13 then
    Exit(ttMovel);
  if L = 15 then
    Val(FNumero[8], D)
  else
    Val(FNumero[5], D);
  if (D >= 2) and (D <= 5) then
    Exit(ttFixo);
  if (D >= 6) and (D <= 9) then
    Exit(ttMovel);
  Result := ttEspecial;
{$ELSE}
  if L <= 2 then
    Result := ttInvalido
  else if L = 3 then
    Result := ttPublico
  else if L < 12 then
  begin
    if NumeroEspecial then
      Result := ttEspecial
    else
      Result := ttInvalido;
  end
  else if L = 13 then
    Result := ttMovel
  else
  begin
    if L = 15 then
      Val(FNumero[8], D, E)
    else
      Val(FNumero[5], D, E);
    if (D >= 2) and (D <= 5) then
      Result := ttFixo
    else if (D >= 6) and (D <= 9) then
      Result := ttMovel
    else
      Result := ttEspecial;
  end;
{$ENDIF}
end;

function TTelefone.GetDescricao: string;
begin
  Result := DESC_TELEFONE[GetTipo];
end;

procedure TTelefone.SetNumero(ANumero: string);
var
  L: Integer;
begin
  ANumero := ApenasString(ANumero);
  if ANumero = '' then
    Exit;
  if Copy(ANumero, 1, 3) = '+55' then
    ANumero := Copy(ANumero, 4, MaxInt);
  FNumero := ApenasNumeros(ANumero);
  L := Length(FNumero);
  if L = 8 then
  begin
    if not NumeroEspecial then
      FNumero := FCodOperadora + FDdd + FNumero;
  end else if L = 9 then
    FNumero := FCodOperadora + FDdd + FNumero
  else if L = 10 then
    FNumero := FCodOperadora + FNumero
  else if (L = 11) or (L = 14) then
    if (not NumeroEspecial) and (Copy(FNumero, 1, 1) = '0') then
    begin
      Delete(FNumero, 1, 1);
      FNumero := FCodOperadora + FNumero;
    end
    else if TemNonoDigito then
      FNumero := FCodOperadora + FNumero;
end;

end.

Example of use:

program test;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}

uses
  Telefone;

  procedure imprime(tel: TTelefone; const num: string);
  begin
    tel.Numero := num;
    WriteLn('NUMERO REAL: ', tel.Numero, ', TIPO: ', tel.Descricao);
  end;

var
  tel: TTelefone;
begin
  tel := TTelefone.Create('41', '65');
  try
    WriteLn('INTRODUZA O NUMERO DO SEGUINTE FORMATO: COD. OPERADORA + COD. AREA + NUMERO');
    WriteLn('=======');
    WriteLn;
    // inválidos
    imprime(tel, '12');
    imprime(tel, '+55 41 (99) 999-9999');
    WriteLn;
    // público
    imprime(tel, '190');
    WriteLn;
    // especial
    imprime(tel, '0300 313 4701');
    imprime(tel, '0500 313 4701');
    imprime(tel, '0800 729 0722');
    imprime(tel, '0900 313 4701');
    imprime(tel, '3003 3030');
    imprime(tel, '4003 3030');
    imprime(tel, '4004 3030');
    WriteLn;
    // fixo
    imprime(tel, '3549-5589');
    imprime(tel, '(87) 3549-5589');
    imprime(tel, '31 (87) 3549-5589');
    WriteLn;
    // movel
    imprime(tel, '9985-0997');
    imprime(tel, '(87) 9985-0997');
    imprime(tel, '31 (87) 9985-0997');
    WriteLn;
    // movel SP
    imprime(tel, '9 9985-0997');
    imprime(tel, '(11) 9 9985-0997');
    imprime(tel, '31 (11) 9 9985-0997');
    imprime(tel, '031 (11) 9 9985-0997');
    imprime(tel, '+55 31 (11) 9 9985-0997');
    imprime(tel, '+55 031 (11) 9 9985-0997');
  finally
    tel.Free;
    ReadLn;
  end;
end.

This code is working perfectly well in an app in production, I hope it will be useful for other colleagues! =)

  • +1 Very good! The problem is that now I will have to work harder on my answer to solve the "bugs" found :P If any more than you mentioned, let me know to improve the Javascript version.

  • Beauty @Zuul, and thanks for the help, because without her I would not have been able to do these classes. = ) You can update the JS version using this version I passed in Java, as the codes are quite compatible. Any doubt I can help you, because in the future I will need the JS version too, to make validations on web pages.

1

I saw many responses, but after a few hours analyzing everything we have on Brazilian phones, I created a function to validate the phones, including:

  • Validation of repeated numbers
  • Character quantity validation (if 10 or 11 numbers, other than characters that do not count)
  • Cellular validation (9th digit) if the number has 11 digits
  • Validation of Ddds (valid Ddds seed) - Thanks @renatoargh
  • Validate if the number is the same phone or the radio type (if the number starts between 2 and 5, or 7) - Valid only after 2017, if ANATEL does everything right

ANATEL hasn’t implemented everything yet, but when someone sees this and is already in 2017 or later (look I’m just talking to someone from the future haha) just delete the line that checks the year, which is referenced in the code.

see an example in operation:Jsfiddle

Also follow Gist for anyone who wants to help improve the code or report errors: Gist

Thanks also to @Leandro Curious, because I based my code on your.

  • Welcome to Stackoverflow. Very good response!

1

I don’t know if your doubt is still in your head, but I found a solution.

I found a website, and it contains a list of Operators, Ddds and Prefix Range in each State, being it SME and/or SMP. From what I noticed, from time to time they release an update of this list, but I downloaded the full ones, both SME and SME, and put them on a table. Below is the link from where I downloaded these files. http://sistemas.anatel.gov.br/sapn/Default.asp?SISQSmodulo=18096&SISQSsistema=288

After that, I made a simple logic in sql. I believe it is easier to show than to explain.

DECLARE
         @Telefone  VARCHAR(12) = 'ddXXXXXXXX' --<-- COLOQUE O TELEFONE AQUI
        ,@DDD       VARCHAR(2)
        ,@Prefixo   VARCHAR(5)
        ,@Final     INT

        SET @DDD        = LEFT(@Telefone, 2)
        SET @Prefixo    = LEFT(RIGHT(@Telefone, 8), 4)
        SET @Final      = RIGHT(@Telefone, 4)

    SELECT 
         Telefone = CONVERT(VARCHAR, DDD) + CONVERT(VARCHAR, Prefixo) + CONVERT(VARCHAR, @Final)
        ,Nome
        ,DDD
        ,Prefixo
        ,Final = @Final
    FROM Operadora 
    WHERE DDD = @DDD
      AND Prefixo LIKE '%' + @Prefixo
      AND @Final BETWEEN Inicial AND Final

I just changed the names of the mailing fields to names usable in tables, but I think it was very intuitive.

In this script, if it has any results at the end, it is because it is a cell phone and it will put the ninth digit in case on the phone it does not come. If you don’t get any results at the end, the number is a fixed number.

Browser other questions tagged

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