Check if a String contains two words

3

I have a problem with this exercise here:

Write a class that does data validation ( Validacao ), with a method to validate a proper name ( ehNomeValido(nome) ). The method should return true if it passes the following rules:

  • If the parameter is not null.

  • If the parameter is not an empty%%

  • If the parameter has two particles (two words separated by a space)

The problem is that the program only returns me String and in the case of the name that I put as a parameter the program should return false . Where am I going wrong? I have already rewritten the code several times in other ways and nothing.

 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"));
  }  
}
    
asked by anonymous 02.07.2018 / 22:10

6 answers

10

This? It seems that the problem is that you are trying to check the wrong thing if you have more than one word.

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

After seeing the solutions and reading the documentation, do some tests I think this form is the simplest and most reliable because it was made to precisely meet this demand. I'm still not sure if you have corner cases .

See running on ideone . And no Coding Ground . Also I placed GitHub for future reference .

StringTokenizer

    
02.07.2018 / 22:19
5

A suggestion with regex, which will probably accept accentuation and will also work with CASE-INSENTIVE, would be like this:

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

You do not even need % in this case with REGEX , if you need exactly two words just change to:

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

If you do not need accenting, then you can use isEmpty , a-z can work as well, but its problem is that it accepts underscore \w , and that does not seem correct in name validation, so the regex can look like this (using _ to case-insensitive can help to decrease complex regular expressions):

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

If you need exactly 2 words, change to:

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

In both examples I have accepted one or more surnames, ie two or more words in the string.

Explaining Regular Expressions

For (?i:...) :

  • ^\p{L}+ [\p{L} ]+$ checks if expression starts with
  • ^ checks words until you find a space (note that after \p{L}+ has a space)
  • + checks for words and spaces, that is, it can contain more than one space word until you find the end of the string

For [\p{L} ]+$ :

  • ^(?i:[a-z]+ [a-z ]+)$ checks if expression starts with
  • ^ starts a group with case-insensitive
  • (?i: checks words with the letters a-z until you find a space (note that after [a-z]+ has a space)
  • + checks words with the letters of a-z and spaces, that is, it can contain more than one word with space until you find the end group (case-insensitive group)
  • [a-z ]+) checks if the string ends exactly as the
02.07.2018 / 22:56
3

indexOf(" ") returns the position where space is in String , so it will not necessarily be 1 . The right thing would be to test if the value is different from -1 , since this is the return value if there are no spaces.

The problem is that indexOf only checks to see if there is any white space. If the entry is " " (multiple spaces), for example, or if the space is at the beginning or end, indexOf will not do any good.

One way to check for two words is to use what @Maniero suggests in his response . Another way is to use regular expression, to make sure that before and after space you actually have a word - assuming that "word" is a sequence of uppercase or lowercase letters:

public static boolean validacao(String nome){
    return (nome != null) && (! nome.isEmpty()) && nome.matches("^[a-zA-Z]+ [a-zA-Z]+$");
}
  • ^ indicates the start of String
  • [a-zA-Z]+ indicates one or more occurrences of uppercase or lowercase
  • $ indicates the start of String

See more details on regular expression in this tutorial . Also note that since the method return is boolean , you can directly return the result of the checks (as well remembered in the comments).

One detail is that the regex will only work for exactly two words. But you can change the $ by .* , which works for several words (there must be at least two).

And will not accept accented characters, as pointed out in the comments.

    
02.07.2018 / 22:22
-1

The problem is in indexOf, it will return the position of the space, which in the case is 7.

I believe the approach below should be more assertive to find the word with just one space

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

indexOf will give -1 or the space the string shows the desired char. In your comparison it only verifies that the space comes after the first letter, eg: jj would do it right, you just need in your comparison to check if the indexOf ("") is different from -1, so:

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

Gandalf, as you are learning, I took the liberty of adjusting the original code and taking the necessary tests (very important).

See how the code went:

public static class NovoTeste2 {

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

In the code above, I simplified the name check to be empty (no need for == false) and, to validate if the name has only two words, I split the String using white space, waiting for the generated array by the split has at least 2 elements. I also changed the class name to a name in the Java standard (using CamelCase).

If you want to restrict to just two words , just switch from length >= 2 to length == 2 .

And finally, the code above with the tests for each case:

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);
        }
    }
}

So it's much easier to know if your code is working even after changes and for all cases provided.

Remember that I did not handle all possible cases: valid name with more than one space between words, extra spaces at the beginning or end of the name, etc.

    
03.07.2018 / 15:17