Trocando caracteres de uma String no Java

(Last Updated On: 14 de dezembro de 2017)

Temos um cadastro que recebe dados como CPF e o CEP do usuário, mas estamos tendo certos problemas no nosso sistema, pois todos os usuários cadastrados estão inserindo seus dados de forma diferente, como mostrado na tabela abaixo:

Nome CPF CEP
Yuri 087824030-66 689.016-60
Mário 959.562.590-60 58030-280

O CPF de cada usuário está sendo enviado em vários formatos e nosso sistema está programado para receber apenas os dígitos do documento, sem nenhum “.” ou “-”.

Alguns endereços não estão sendo encontrados, pois para buscar o endereço do usuário é necessário que o CEP esteja sem formatação alguma, ou seja, só possua os dígitos.

Precisamos padronizar isso para que todos sejam salvos da mesma forma.

Para isso, vamos criar um método que pega os dados do usuário e os formata, retirando tudo o que for desnecessário, antes dos mesmos serem enviados para alguma lógica de negócio.

Todos os dados que receberemos serão do tipo String, portanto vamos criar um método que recebe uma String, formata e a retorna:


public static String formataDados(String dado){
   //lógica de formatação aqui
   return dado;
}

Vamos começar pelo CPF. Um CPF é composto por 11 dígitos, que podem estar separados, tanto por “.” quanto por “-”. E aí, como removeremos esses caracteres indesejados?

Método replaceAll()

Precisamos sumir com os caracteres indesejados sem remover nenhum dígito ou mudar a ordem dos caracteres da nossa String. Para isso podemos usar o método replaceAll() da classe String.

Este método nos permite substituir todas as ocorrências do caractere que passarmos por outro caractere.

Então primeiro vamos remover todos os “.”. Dessa forma temos:


public static String formataDados(String dado){
   dado = dado.replaceAll(".","");
   return dado;
}

Perceba que o primeiro argumento que passamos foi “.”, pois ele é o caractere que queremos substituir. Logo em seguida passamos uma String vazia representada pelas aspas duplas juntas.

Com isso estamos dizendo que qualquer ponto que ele ache na nossa String será substituído por nada, logo, será removido.

Para testar, vamos chamar este método passando um CPF qualquer:


public static void main(String[] args) {
   System.out.println(formataDados("157.108.950-08"));
}

Como resultado temos:

Nada… Cadê nossa String formatada? Isso ocorreu pois o replaceAll() também aceita expressões regulares (regex).

Neste caso, ele considerou o ponto como uma expressão regular. Este regex representa qualquer caractere menos \n que representa uma nova linha. Com isso todos os caracteres da nossa String foram removidos.

Precisamos fazer o Java interpretar o ponto como apenas um ponto e não um regex, para isso vamos adicionar duas barras invertidas antes do ponto, isso indica para o compilador que o ponto tem um significado diferente do padrão, que naquele caso, é um regex. Logo ele vai considerar o ponto como um caractere normal, desta forma:


public static String formataDados(String dado){
   dado = dado.replaceAll("\\.","");
   return dado;
}

Vamos testar novamente e ver o que acontece:

Conseguimos. Agora vamos fazer o mesmo para o “-“. Este é mais simples pois o hífen não corresponde a nenhum regex. Então o Java não vai se confundir. Nos resta apenas colocar mais um replaceAll():


public static String formataDados(String dado){
   dado = dado.replaceAll("\\.","");
   dado = dado.replaceAll("-", "");
   return dado;
}

Vamos testar com o mesmo CPF:

Pronto, conseguimos formatar nosso CPF e de quebra formatamos o CEP também.

Se pensarmos num CEP ele tem essa estrutura: “13508-970”. Então quando ele entrar no segundo replaceAll() o hífen será removido.

Vamos testar essa teoria passando um CEP verdadeiro:


public static void main(String[] args) {
   System.out.println(formataDados("13508-970"));
}

E no nosso console:

Problemas da nossa resolução

Parece estar tudo certo, não é mesmo?. Mas um usuário é imprevisível. Por exemplo, o que aconteceria se eu mandasse um cep com “/” ou com alguma letra? Vamos ver:


public static void main(String[] args) {
   System.out.println(formataDados("13/508-970"));
}

Resultado:

Não tratamos esse caso, e se o dado tiver letras? Tiver outro símbolo estranho? Teremos que fazer um replaceAll para cada caractere que possa burlar nossa formatação?

Perceba que nosso plano está ficando inviável. É muito difícil conseguirmos cobrir todos os casos que possam quebrar nosso método de formatação. Talvez estejamos pensando errado.

Lidando com dados imprevisíveis

Que tal, ao invés de falar os caracteres que não permitimos, falarmos os caracteres que permitimos para nosso método replaceAll()? Com isso ele eliminaria tudo que fosse desnecessário ou inválido.

Pensando em um CPF ou em um CEP, o que eles permitem ter? Apenas dígitos, correto? Logo, vamos falar para o replaceAll() que queremos substituir tudo o que não for dígito por nada, ou seja, queremos remover tudo que não for dígito:


public static String formataDados(String dado){
   return dado.replaceAll("[^0-9]+", "");
}

Esse regex representa tudo o que não for um número de 0 a 9. Para testar, vamos passar um CPF cheio de erros, com “.”, ”-”, ”/” e letras:


public static void main(String[] args) {
   System.out.println(formataDados("15/*7.1DAS08.950-08/A?%D"));
}

Nosso método nos devolve:

Funcionou! Conseguimos fazer nosso método formatar de forma correta.

Conclusão

Formatar dados é algo muito comum. É preciso tomar cuidado ao lidar com dados vindos do usuário, pois nunca se sabe o que o usuário está mandando. Também, ao se envolver em um problema desses, onde está ficando cada vez mais difícil criar ou dar manutenção em uma funcionalidade, é muito válido parar e ver o problema por outro ângulo, como foi o nosso caso.

É muito importante saber construir um código limpo e conseguir perceber um problema no nosso próprio código. Para nos ajudar nisso a Alura possui o Curso Design Patterns Java I: Boas práticas de programação. Lá você aprenderá muito sobre design patterns e boas práticas em Java.

FIQUE POR DENTRO

  • Camelo Rodoviário

    Hoje era 5 da manhã e eu gritando com o notebook porque diabos o replaceAll(“.”) estava sumindo com meu valor haha

    • Mario Alvial

      Hahahahahahahaahah, eu fiz o mesmo na primeira vez que precisei substituir um ponto. Acontece com os melhores, boa!

  • Carlos Henrique dos Santos Lim

    Eu criei uma classe static Mask para cpf e cep para evitar que o ususario digite uma formatação errada. Por exemplo:
    String cpf = Mask.inputMask(“###.###.###-##”);
    String cep = Mask.inputMask(“#####-###”);

    Como boas praticas o que eu fiz esta certo?

    • Mario Alvial

      Está ótimo, você isolou um comportante em uma classe só. Olha como ficou fácil você conseguir que o usuário não digite com uma formatação errada. Parabéns!

Próximo ArtigoApresentando seu app com Walkthroughs