O contador de consoantes não esta contando corretamente(Java)

O objetivo da atividade era verificar se o nome que tem 3 consoantes seguidas e com isso definir que o nome era dificil caso não seria facil mas por alguma razão na hora de contar as consoantes, também esta contando as vogais

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int cons = 0;
        Boolean verifica = true;
        for(int i = 0; i < N; i++){
            String nome = in.next();
            String nomeL = nome.toLowerCase();
            for(int k = 0; k < nome.length(); k++){
                char c = nomeL.charAt(k);
                if(c != 'a' || c != 'e' || c != 'i' || c != 'o' || c != 'u'){
                    cons++;
                    if(cons >= 3){
                        verifica = false;
                        break;
                    }
                }
                else{
                    cons = 0;
                    verifica = true;
                } 
            }
            if(!verifica){
                System.out.println(nome + " nao eh facil");
            }
            else{
                System.out.println(nome + " eh facil");
            }

        }
    }
}

1 curtida

você zero a variavel no ELSE! percebeu isso?

Qual quer caracter vai ser sempre true aqui uma vez que de certeza que é
diferente de 'a' ou diferente de 'e' ou diferente de 'i'

Tu queres contar as que são
diferente de 'a' e diferente de 'e' e diferente de 'i'

1 curtida

Recomendo usar substring acho mais facil de trabalhar.

1 curtida

A resposta do @pmlm já indica onde está seu problema.

De forma geral, evite ifs com condições grandes, especialmente misturando NOT (!) e OR (||).
É muito comum confundir o que está sendo testado.

Talvez te facilite se você usar apenas um NOT por expressão.

No seu caso, você quer testar se uma letra é vogal. Para usar apenas um NOT, como faz? Teste que a letra é vogal (com OR) e apenas uma vez use NOT (ou seja: não é vogal).

boolean ehVogal = c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
boolean naoEhVogal = !ehVogal;

Isso está correto de acordo com a descriçao do problema: “…era verificar se o nome que tem 3 consoantes seguidas…”

Provavelmente isto é um exercício académico e o objetivo é mesmo usar for e if mas fica a dica de que quando, na vida real, surgir algo deste género, é bem mais simples usar expressões regulares:

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();

    for (int i = 0; i < n; i++) {
        String nome = in.next().toLowerCase();

        if (nome.matches("^.*[^aeiou]{3}.*$")) {
            System.out.println(nome + " nao eh facil");
        } else {
            System.out.println(nome + " eh facil");
        }
    }
}
1 curtida

Perfeito apresentou melhorias sem atacar ninguém, parabéns!

Como já foi explicado, o operador deveria ser && em vez de || (você quer que o caractere seja diferente de “a” e diferente de “e” e diferente de “i” etc, mas vc está testando com “ou” - se a letra for, por exemplo, “e”, ela é diferente de “a” e só isso já faz entrar no if, pois com o operador || basta que uma das condições seja verdadeira).

Mas ainda tem outro porém. Mesmo se eu fizer if (c != 'a' && c != 'e' && c != 'i' && c != 'o' && c != 'u'), ainda sim tem casos que não vai contar corretamente. Isso porque, como o usuário pode digitar qualquer coisa, nada impede que digite, por exemplo, bc1 ou !@#. E tanto o dígito 1 quanto os caracteres !@# entrarão neste if e serão considerados “consoantes”. O if só funciona corretamente se a string tiver apenas letras, mas se tiver qualquer outro caractere, não funciona mais.

Em exercícios isso não costuma ser uma preocupação, já que geralmente esse tipo de coisa só é testada com textos válidos (no caso, contendo apenas letras). Mas acho importante se acostumar a pensar um pouco além do “caminho feliz” (aquele no qual todos os dados são válidos e vc não precisa se preocupar em validar nada). Todo programa que aceita entradas do usuário deve estar preparado para receber qualquer coisa e só deixar passar o que for válido.

Então primeiro você precisa ver se de fato é uma letra, para só depois excluir as vogais. Além disso, não precisa desse booleano verifica, pois você pode usar a própria contagem para saber se encontrou as 3 consoantes consecutivas. Algo assim:

public static boolean isConsoante(char c) {
    if ('A' <= c && c <= 'Z') { // se é letra maiúscula, converte para minúscula
        c = Character.toLowerCase(c);
    }
    if ('a' <= c && c <= 'z') { // se é letra, verifica se é vogal
        // se não for nenhuma das vogais, então é consoante
        return c != 'a' && c != 'e' && c != 'i' && c != 'o' && c != 'u';
    }
    // se não entrou no if acima, não é letra, e portanto não é consoante
    return false;
}

public static void main(String args[]) throws Exception {
    Scanner in = new Scanner(System.in);
    int n = in.nextInt();
    for (int i = 0; i < n; i++) {
        String nome = in.next();
        int consoantesSeguidas = 0;
        for (int j = 0; j < nome.length(); j++) {
            if (isConsoante(nome.charAt(j))) {
                consoantesSeguidas++;
                if (consoantesSeguidas == 3) {
                    break;
                }
            } else {
                consoantesSeguidas = 0;
            }
        }

        if (consoantesSeguidas == 3) {
            System.out.println(nome + " não é fácil");
        } else {
            System.out.println(nome + " é fácil");
        }
    }
}

Separei a lógica de verificar se é consoante em um método, acho que fica um pouco mais legível do que se estivesse tudo dentro do for.


Se for para usar a regex que foi sugerida (que também tem o mesmo porém, de considerar 1@#! como consoantes), precisaria de uma modificação:

Scanner in = new Scanner(System.in);
int n = in.nextInt();
// não esqueça de dar import em java.util.regex.Pattern e java.util.regex.Matcher
Matcher matcher = Pattern.compile("[a-z&&[^aeiou]]{3}", Pattern.CASE_INSENSITIVE).matcher("");
for (int i = 0; i < n; i++) {
    String nome = in.next();
    if (matcher.reset(nome).find()) {
        System.out.println(nome + " não é fácil");
    } else {
        System.out.println(nome + " é fácil");
    }
}

No caso, a expressão [a-z&&[^aeiou]] pega todas as letras de “a” a “z”, exceto as vogais (claro que também poderia ser [bcdfghjklmnpqrstvwxyz], mas achei a primeira mais sucinta), e {3} pega três ocorrências seguidas. A opção Pattern.CASE_INSENSITIVE faz com que considere tanto letras maiúsculas quanto minúsculas.

Claro que também daria para usar nome.matches(...), a diferença é que este método compila a regex toda hora (sim, toda regex é compilada - não só em Java, mas em todas as linguagens que possuem este recurso - e convertida para uma estrutura interna). Já usando o Pattern, a regex só é compilada uma vez e reaproveitada.


Novamente, vale ressaltar que em um exercício (no qual geralmente só se usam entradas válidas para testar) isso talvez não seja tão importante, pois provavelmente só vão testar com strings que contém apenas letras. Mas de qualquer forma fica a dica de sempre pensar um pouco além, principalmente se o programa recebe dados do usuário e que este pode digitar basicamente “qualquer coisa” (seja sem querer, seja de propósito).