TransWikia.com

Verificar se uma String contém duas palavras

Stack Overflow em Português Asked on December 16, 2021

Estou com um problema nesse exercício aqui:

Escreva uma classe que faça a validação de dados (Validacao), com um método para validar um nome próprio (ehNomeValido(nome)). O método deve retornar true se passar pelas seguintes regras:

  • Se o parâmetro não for nulo.

  • Se o parâmetro não for uma String vazia

  • Se o parâmetro tiver duas partículas (duas palavras separadas por um espaço)

O problema é que o programa só me retorna o false sendo que no caso do nome que eu coloquei como parâmetro o programa deveria retornar true. Onde estou errando? Já rescrevi o código várias vezes de outras formas e nada.

 public class NOVOTESTE2{

     public static boolean validacao(String nome){
         if((nome != null) && (nome.isEmpty() == false) && (nome.indexOf(" ") == 1)){
             return true;
         }else{
             return false;
         }     
     }

  public static void main(String[] args){

        System.out.println(validacao("Rodrigo Moreira"));
  }  
}

6 Answers

Gandalf, como está aprendendo, tomei a liberdade de ajustar o código original e fazer os testes necessários (muito importante).

Veja como ficou o código:

public static class NovoTeste2 {

    public static boolean validacao(String nome){
        return (nome != null) && (!nome.isEmpty()) && (nome.split(" ").length >= 2);
    }
}

No código acima, simplifiquei a verificação do nome estar vazio (não precisa do == false) e, para validar se o nome tem apenas duas palavras, fiz um split da String usando o espaço em branco, esperando que o array gerado pelo split tenha ao menos 2 elementos. Também alterei o nome da classe para um nome no padrão Java (usando CamelCase).

Se quiser restringir para apenas duas palavras, basta trocar de length >= 2 para length == 2.

E por fim, o código acima com os testes para cada caso:

public class TemAoMenosDuasPalavrasTest {

    @Test
    public void nomeCorreto() {
        assertTrue(NovoTeste2.validacao("Augusto Nonato"));
    }

    @Test
    public void nomeComTresPalavras() {
        assertTrue(NovoTeste2.validacao("Augusto Nonato Junior"));
    }

    @Test
    public void nomeSemDuasPalavras() {
        assertFalse(NovoTeste2.validacao("Augusto"));
    }

    @Test
    public void nomeNulo() {
        assertFalse(NovoTeste2.validacao(null));
    }

    @Test
    public void nomeVazio() {
        assertFalse(NovoTeste2.validacao(""));
    }

    @Test
    public void nomeVazioComEspacos() {
        assertFalse(NovoTeste2.validacao("   "));
    }

    public static class NovoTeste2 {

        public static boolean validacao(String nome){
            return (nome != null) && (!nome.isEmpty()) && (nome.split(" ").length >= 2);
        }
    }
}

Assim, fica muito mais fácil saber se o seu código está funcionando mesmo após alterações e para todos os casos previstos.

Lembrando que não tratei todos os possíveis casos: nome válido com mais de um espaço entre as palavras, espaços extras no início ou final do nome, etc.

Answered by Dherik on December 16, 2021

Uma sugestão com regex, que provavelmente vai aceitar acentuação e também irá trabalhar com CASE-INSENTIVE, seria usando assim:

public static boolean validacao(String nome){
    return nome != null && nome.matches("^\p{L}+ [\p{L} ]+$"));
}

Nem é necessário o isEmpty nesse caso com REGEX, se precisar de exatamente duas palavras mude apenas para:

nome.matches("^\p{L}+ \p{L}+$"))

Se não precisar de acentuação, então pode usar o a-z, o w pode funcionar também, mas o problema dele é que ele aceita underscore _, e isso não me parece correto em uma validação de nome, então a regex pode ficar assim (usando o (?i:...) para case-insensitive pode ajudar a diminuir expressões regulares complexas):

public static boolean validacao(String nome){
    return nome != null && nome.matches("^(?i:[a-z]+ [a-z ]+)$"));
}

Se necessitar de exatamente 2 palavras mude para:

nome.matches("^(?i:[a-z]+ [a-z]+)$"))

Em ambos exemplos fiz aceitam um ou mais sobrenomes, ou seja duas ou mais palavras na string.


Explicando as expressões regulares

Para a ^\p{L}+ [\p{L} ]+$:

  • ^ verifica se a expressão começa com
  • \p{L}+ verifica palavras até encontrar um espaço (note que após o + tem um espaço)
  • [\p{L} ]+$ verifica palavras e espaços, ou seja pode conter mais de uma palavra com espaço até encontrar o final da string

Para a ^(?i:[a-z]+ [a-z ]+)$:

  • ^ verifica se a expressão começa com
  • (?i: inicia um grupo com case-insensitive
  • [a-z]+ verifica palavras com as letras de a-z até encontrar um espaço (note que após o + tem um espaço)
  • [a-z ]+) verifica palavras com as letras de a-z e espaços, ou seja pode conter mais de uma palavra com espaço até encontrar o final do grupo (grupo para case-insensitive)
  • $ verifica se a string termina exatamente conforme a expressão

Answered by Guilherme Nascimento on December 16, 2021

O problema é no indexOf, Ele vai retornar a posição do espaço, que no casó é 7.

Acredito que a abordagem abaixo deve ser mais assertiva para encontrar a palavra com apenas um espaço

    public static boolean validacao(String nome){
        if(nome != null && !nome.isEmpty() && nome.split(" ").length == 2){
            return true;
        }else{
            return false;
        }
    }

Answered by MarlonJhow on December 16, 2021

indexOf(" ") retorna a posição em que o espaço está na String, portanto não necessariamente será 1. O certo seria testar se o valor é diferente de -1, já que este é o valor retornado caso não haja espaços.

O problema é que indexOf só verifica se existe algum espaço em branco.
Se a entrada for " " (vários espaços), por exemplo, ou se o espaço estiver no início ou no final, indexOf não vai adiantar nada.

Uma maneira de verificar se tem duas palavras é usar o que o @Maniero sugere na resposta dele. Outro jeito é usar expressão regular, para ter certeza que antes e depois do espaço você tem de fato uma palavra - assumindo que "palavra" é uma sequência de letras maiúsculas ou minúsculas:

public static boolean validacao(String nome){
    return (nome != null) && (! nome.isEmpty()) && nome.matches("^[a-zA-Z]+ [a-zA-Z]+$");
}
  • ^ indica o início da String
  • [a-zA-Z]+ indica uma ou mais ocorrências de letras maiúsculas ou minúsculas
  • $ indica o início da String

Veja mais detalhes sobre expressão regular neste tutorial. Repare também que, como o retorno do método é um boolean, você pode retornar diretamente o resultado das verificações (conforme bem lembrado nos comentários).

Um detalhe é que a regex só vai funcionar para exatamente duas palavras. Mas você pode trocar o $ por .*, que aí funciona para várias palavras (sendo que deve ter no mínimo duas).

E não vai aceitar caracteres acentuados, conforme apontado nos comentários.

Answered by hkotsubo on December 16, 2021

indexOf dará -1 ou o espaço que a string mostrar o char desejado. Na sua comparação ele só verifica que o espaço vem depois da primeira letra, exemplo: j joão daria certo, vc só precisa na sua comparação verificar se o indexOf(" ") é diferente de -1, logo:

public static boolean validacao(String nome){
         if ((nome != null) && (nome.isEmpty() == false) && (nome.indexOf(" ") != -1)){
             return true;
         } else {
             return false;
         }     
     }

Answered by Gustavo Freire on December 16, 2021

Isto? Parece que o problema é que está tentando verificar coisa errada se tem mais de uma palavra.

public static boolean validacao(String nome) {
    return nome != null && !nome.isEmpty() && new StringTokenizer(nome).countTokens() > 1;
}

Depois de ver as soluções e ler documentação, fazer uns testes acho que esta forma é a mais simples e confiável porque foi feita para atender justamente esta demanda. Ainda não tenho certeza se tem corner cases.

Veja funcionando no ideone. E no repl.it. Também coloquei no GitHub para referência futura.

StringTokenizer

Answered by Maniero on December 16, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP