Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

1. Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Mariana Ribeiro Mendes
meldenne

(usa Linux Mint)

Enviado em 21/09/2012 - 17:28h

Olá Pessoal,
Há um tempo atrás eu estava criando este algoritmo, é algo bem simples, a ideia inicial era que ele lê-se uma frase digitada pelo usuário e contasse quantas consoantes e vogais ali existem. A única exceção era que o usuário não deveria digitar os acentos e nem o ç/Ç (pois seriam ignorados). Bom, isso ele já faz... Mas então 'eu resolvi' que ele deveria ler os acentos e o ç/Ç. E aí começaram os problemas...
Vejam bem, eu testei comparando char... Deu errado!
Testei, comparando o valor que eles assumem na tabela ASCII, uau... Deu errado de novo!
Testei comparando o valor UTF-16... E deu errado de novo!
Estes testes foram os que lembro de ter feito, pesquisei bastante na internet e as soluções que encontrei tentei implementar mas não deram certo.
Vocês sabem de algo que possa me ajudar?

Também há outro problema, na leitura, caso uma letra acentuada ou ç/Ç sejam a última letra da frase, o usuário deve digitar 2 'enter' para que a execução continue... Queria poder solucionar isso. Alguém sabe o porque isso acontece ou como solucionar?

Não peço código, apenas um caminho para que eu possa seguir... Já deixei este algoritmo parado por bastante tempo e gostaria de terminá-lo para postar aqui.

Abaixo segue o código completo, está meio extenso pois não retirei os comentários que eu havia feito. No mais, o código em si é bem simples. Nada que lhes vá render muita dor de cabeça. Caso seja um erro no próprio código, ficaria feliz que me dissessem, mas ele está funcionando perfeitamente (cumpre o que promete, conta as vogais e as consoantes de uma frase com no máximo 80 caracteres e mostra o resultado na saída).

Desde já agradeço.



//Importa a classe Scanner para realizar leituras do teclado.
import java.util.Scanner;

/**
* Este algoritmo recebe uma palavra ou frase e conta quantas vogais e consoantes
* há nesta palavra/frase. Nota-se que por ser um algoritmo simples ele não reconhece
* acentos, nem 'ç' ou 'Ç', ou seja... Ele irá ignorá-los. Caso uma letra acentuada ou
* um ç/Ç sejam a última entrada, ele esperará um segundo 'enter' depois da indicação
* de fim de linha para iniciar a execução.
* O tamanho máximo da palavra/frase deverá ser de 80 caracteres.
* É um algoritmo simples, e eu particulamente não gosto muito de 'switch', mas o preferi
* aos vetores e suas comparações. Achei ser mais eficiente. Estou aberta a outras dicas.
* Caso hajam erros, por favor avisem, para que eu os possa corrigir.
*/
public class LetrasASCII {

/**
* Este método estático, recebe um char e retorna true, caso o char seja
* encontrado nas comparações do switch. Neste caso, não é necessário utilizar
* o break, pois, assim que o char é encontrado da lista ele é retornado e a
* verificação termina.
* @param v
* @return boolean
*/
public static boolean verificaVogal(char v) {

switch (v) {

case 'a':
return true;

case 'e':
return true;

case 'i':
return true;

case 'o':
return true;

case 'u':
return true;

}

return false;

}

/**
* Este método recebe uma String como parametro e conta quantas consoantes e
* quantas vogais existem nessa String. Lá em cima, eu criei um método para
* fazer a contagem das vogais e um para as consoantes porque assim facilitaria
* aqui neste método fazer a contagem das mesmas. E também diminuiria o número
* de comparações do 'char atual' caso fosse uma vogal, como veremos mais abaixo.
* @param frase
*/
public static void contaLetras(String frase) {

//Inicialização de variáveis
int vogal = 0, consoante = 0;

/**
* Este for irá percorrer toda a extensão da String enquanto o contador
* for menor que o tamanho da String.
*/
for (int cont = 0; cont < frase.length(); cont++) {


//Verifica se o caracter na posição cont da palavra/frase está entre 'A' e 'Z' ou 'a' e 'z'
if (((frase.toLowerCase().charAt(cont) >= 'a') && (frase.toLowerCase().charAt(cont) <= 'z'))) {

/**
* Se ele passar no teste acima ele chama o método verificaVogal()
* para descobrir se este char é uma vogal. Se o método retornar
* true, +1 é adicionado à variavel vogal. Senão, +1 é adicionado
* à consoante.
*/
if (verificaVogal(frase.toLowerCase().charAt(cont))) {

vogal++;

} else {

consoante++;

}
}
}

//Lista quantas vogais e consoantes há na frase.
System.out.println("Vogais: " + vogal + " Consoante: " + consoante);

/**
* xD Não deixa o algoritmo terminar de qualquer forma. Chama o menu
* que pergunta ao usuário se ele deseja continuar com a execução.
*/
retornoMenu();

}

/**
* Este método cria um pequeno menu que é chamada ao fim do programa. Assim o
* usuário poderá indicar se quer finalizar se quer terminar o programa ou
* continuar com uma nova frase.
*/
public static void retornoMenu() {

//Instancia um objeto Scanner para leitura do teclado.
Scanner in = new Scanner(System.in);
System.out.println("Deseja fazer outro teste? [s/n]");
//Lê do teclado a resposta do usuario.
String teste = in.nextLine();

/**
* Aqui é testado se o usuário digitou corretamente as opções
* para que a execução continue ou não.
*/
if (teste.toLowerCase().equals("s") || teste.toLowerCase().equals("n")) {

/**
* Caso ele passe no teste acima, ele verifica se o usuário digitou
* 's' ou 'n'. Caso seja 's', ele apenas chama o método início e volta
* para o início do fluxo de execução. Se for 'n', ele imprime na saída
* que é o fim do programa e termina.
*/
if (teste.toLowerCase().equals("s")) {

inicio();

} else {

System.out.println("Fim do programa...");

}

/**
* Caso ele não não digite as opções corretamente, o programa avisa que
* ouve um erro e chama esta função novamente.
*/
} else {

System.out.println("Informação Inválida! Digite apenas 's' ou 'n'.");
retornoMenu();

}
//Fim

}

/**
* Este método dá início ao programa, é ele quem faz a leitura da frase
*/
public static void inicio() {

//Variável para guardar a frase.
String frase;

//Instancia um objeto da classe Scanner para ler as entradas do teclado.
Scanner in = new Scanner(System.in);

//Gera uma saída na tela
System.out.println("Entre com a frase, por favor. Não utilize acentos e não ultrapasse o limite de 80 caracteres");

/**
* Aqui a variável frase receberá o que o usuário digitar. A instancia da classe Scanner, que no caso é 'in',
* chamará o método nextLine() que retornará para a variável o que está na entrada.
*/
frase = in.nextLine();

/**
* Faz uma verificação para confirmar que a frase não tem mais de 80 caracteres.
* Caso tenha ela retorna uma mensagem de aviso e retorna ao início do algoritmo para que
* o usuário possa realizar outra entrada.
*/
if (frase.length() > 80) {

System.out.println("A frase contém mais que 80 caracteres. ");
inicio();

}

//Chama o método que irá contar as letras da frase, caso ela esteja ok.
contaLetras(frase);

}

public static void main(String[] args) {

//Chama o método inicio(), onde começa o algoritmo.
inicio();

}
}



  


2. MELHOR RESPOSTA

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 21/09/2012 - 18:31h

Voltando ao caso em questão, você pode converter os caracteres acentuados em não acentuados e testá-los. Como indica aqui: http://www.guj.com.br/java/48001-comparar-strings-com-e-sem-acento

3. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 21/09/2012 - 18:21h

Olha, eu não sei como resolver teu problema, mas, se me permite criticar seu código, você colocou o método inicio() dentro dele mesmo caso a frase tenha mais de 80 caracteres, acho isso deselegante e um má prática de programação. Chamada de função ou métodos recursivamente deve ser implementado quando se quer repeti-lo até gerar um resultado final, como fibonance.

E novamente você coloca o método início() dentro de outro método, o retornoMenu() e este dentro do contaLetra(). Isso vai gerar vários problemas, porque a execução nunca sairá de um método ou de outro. Se você repetir o retornoMenu() várias vezes, o programa estará preso no primeiro método ainda, gerando desperdício de memória.

Desculpe te dizer, mas o seu código está uma salada de fruta. Como é pequeno não vai ter problema na leitura do mesmo, mas se mantiver essa prática, os códigos longos ficarão praticamente ilegíveis.

Lembre-se, código bem escritos, são aqueles que qualquer um da área possa ler sem dificuldades.

O mais indicado é fazer um loop com 'do while()', colocando as condições necessárias para voltar ao loop. Dessa forma, os métodos só sarão executados uma vez por loop.


4. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Mariana Ribeiro Mendes
meldenne

(usa Linux Mint)

Enviado em 22/09/2012 - 07:01h

rei_astro escreveu:

Olha, eu não sei como resolver teu problema, mas, se me permite criticar seu código, você colocou o método inicio() dentro dele mesmo caso a frase tenha mais de 80 caracteres, acho isso deselegante e um má prática de programação. Chamada de função ou métodos recursivamente deve ser implementado quando se quer repeti-lo até gerar um resultado final, como fibonance.

E novamente você coloca o método início() dentro de outro método, o retornoMenu() e este dentro do contaLetra(). Isso vai gerar vários problemas, porque a execução nunca sairá de um método ou de outro. Se você repetir o retornoMenu() várias vezes, o programa estará preso no primeiro método ainda, gerando desperdício de memória.

Desculpe te dizer, mas o seu código está uma salada de fruta. Como é pequeno não vai ter problema na leitura do mesmo, mas se mantiver essa prática, os códigos longos ficarão praticamente ilegíveis.

Lembre-se, código bem escritos, são aqueles que qualquer um da área possa ler sem dificuldades.

O mais indicado é fazer um loop com 'do while()', colocando as condições necessárias para voltar ao loop. Dessa forma, os métodos só sarão executados uma vez por loop.


Obrigada pela sugestão, vou melhorá-lo.

n.n


5. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Mariana Ribeiro Mendes
meldenne

(usa Linux Mint)

Enviado em 22/09/2012 - 20:58h

rei_astro escreveu:

Olha, eu não sei como resolver teu problema, mas, se me permite criticar seu código, você colocou o método inicio() dentro dele mesmo caso a frase tenha mais de 80 caracteres, acho isso deselegante e um má prática de programação. Chamada de função ou métodos recursivamente deve ser implementado quando se quer repeti-lo até gerar um resultado final, como fibonance.


Olá Senhor,
Desculpe incomodá-lo novamente com isso, em relação ao desperdício de memória, eu modifiquei o código... Olhe só:


import java.util.Scanner;

public class LetrasASCII {


public static boolean verificaVogal(char v) {

switch (v) {

case 'a':
return true;

case 'e':
return true;

case 'i':
return true;

case 'o':
return true;

case 'u':
return true;

}

return false;

}


public static void contaLetras(String frase) {

int vogal = 0, consoante = 0;
String teste;
Scanner in = new Scanner(System.in);

for (int cont = 0; cont < frase.length(); cont++) {

if (((frase.toLowerCase().charAt(cont) >= 'a') && (frase.toLowerCase().charAt(cont) <= 'z'))) {

if (verificaVogal(frase.toLowerCase().charAt(cont))) {

vogal++;

} else {

consoante++;

}
}
}


System.out.println("Vogais: " + vogal + " Consoante: " + consoante);

do {

System.out.println("Deseja fazer outro teste? [s/n]");
teste = in.nextLine();

if (teste.toLowerCase().equals("s") || teste.toLowerCase().equals("n")) {

if (teste.toLowerCase().equals("s")) {

inicio();

} else {

System.out.println("Fim do programa...");

}


} else {

System.out.println("Informação Inválida! Digite apenas 's' ou 'n'.");

}

} while ((!teste.toLowerCase().equals("n")));


}


public static void inicio() {

String frase;
Scanner in = new Scanner(System.in);
do {
System.out.println("Entre com a frase, por favor. Não utilize acentos e não ultrapasse o limite de 80 caracteres");
frase = in.nextLine();


if (frase.length() > 80) {

System.out.println("A frase contém mais que 80 caracteres. ");

}

} while (frase.length() > 80);

contaLetras(frase);

}

public static void main(String[] args) {

inicio();

}
}



Assim está melhor, ou ainda há alguma parte que prende a execução? É que quando eu fiz o algoritmo eu não havia pensado nisso, apenas em resolver o problema. Quanto à solução que o senhor achou no GUJ, eu ainda não tive tempo de implementar uma das soluções, achei bem interessante a classe Collator, provavelmente ela irá resolver o problema. Já quanto ao problema na entrada o senhor nem imagina uma solução?

Ah, só sobrou este husauhsha teria algum problema?

//[...]
if (teste.toLowerCase().equals("s")) {

inicio();
//[...]



Desde já agradeço.



6. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 22/09/2012 - 21:59h

Seu código melhorou, mas enquanto houver uma chamada do método inicial dentro de outro método, a primeira chamada ficará sempre aberta e o outro método também. A intenção é executar apenas um método por vez até que o mesmo seja fechado para iniciar outro.

Abaixo tento colocar um exemplo de como ficaria:


public static void inicio() {
String frase;
Scanner in = new Scanner(System.in);
char op;
do{ //este laço executa até o usuário escolher 'n' para op
do{ //este laço executa enquanto digitar mais de 80 caracteres
System.out.println("Digite uma frase com até 80 caracteres");
frase = in.nextLine();
if (frase.length() > 80){ //se digitar mais de 80 caracteres, volta a pedir a frase
System.out.println("A frase contém mais que 80 caracteres. Digite novamente!");
}
else{ //se digitar menos de 80 caracteres, chama o método de contar as letras
contaLetras(frase);
}
}
while(frase.length() > 80);
do{//este laço executa enquanto o usuário não digita 's' nem 'n' para op
System.out.println("Deseja fazer outro teste? [s/n]");
op = in.nextLine();
if(op != 's' && op != 'n'){
System.out.println("Opção inválida!");
}
}
while(op != 's' && op != 'n');
}
while(op == 's');
}


Verifique se não digitei nada errado.

Não me lembro do problema na entrada. Me recorde.

Só por curiosidade. Já verificou se o código conta espaços em branco?


7. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 22/09/2012 - 22:09h

Interessante também seria deixar os métodos contaLetras() só para retornar o resultado. Nesse caso retornaria uma string:


...
return "Vogais: " + vogal + " Consoante: " + consoante;
...


E no método inicio() pediria para imprimi-lo na tela:


...
System.out.println(contaLetras(frase));
...



8. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Mariana Ribeiro Mendes
meldenne

(usa Linux Mint)

Enviado em 22/09/2012 - 23:24h


Verifique se não digitei nada errado.

Não me lembro do problema na entrada. Me recorde.

Só por curiosidade. Já verificou se o código conta espaços em branco?


[/quote]

Ele só conta letras e vogais, já fiz a verificação. Ele ignora os espaços em branco ou qualquer outra coisa.

O problema da entrada (que não sei se haverá solução) é que se a última letra a ser digitada for uma vogal acentuada ou um ç/Ç o usuário tem que clicar no 'enter' duas vezes para que a entrada seja lida. Mas, só tive esse problema no Netbeans, agora que estou utilizando o Eclipse, por enquanto está tudo certo.

n.n

Vou dar mais uma verificada no código, confirmar se não há realmente nenhum erro de lógica, e quando eu modificar isso do método e 'ajeitar' a questão das palavras acentuadas eu coloco o post como resolvido.

Obrigada pela ajuda, senhor.


9. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 23/09/2012 - 00:48h

Disponha. Estou a disposição para ajudar no que poder. Não esqueça de mencionar e comentar se as modificações deram certo, inclusive as que sugeri.

Boa sorte.


10. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Mariana Ribeiro Mendes
meldenne

(usa Linux Mint)

Enviado em 23/09/2012 - 15:39h

rei_astro escreveu:

Disponha. Estou a disposição para ajudar no que poder. Não esqueça de mencionar e comentar se as modificações deram certo, inclusive as que sugeri.

Boa sorte.


Ah, deram certo sim. Muito obrigada. Aquela dica foi valiosa, todas elas, aliás...
Segue o código final. Espero que esteja um pouco mais 'ajeitado' shuahsahu. Nos meus testes deu tudo certo, sinta-se livre para testá-lo novamente. n.n

Muito Obrigada.


import java.text.Collator;
import java.util.Scanner;

public class LetrasCollator {


static Collator collator = Collator.getInstance();

public static boolean testeConsoante(String letra){

if (collator.compare(letra, "ç") == 0){

return true;

}

return false;

}

public static boolean testeVogal(String letra){

switch (letra) {

case "á":

if (collator.compare(letra, "á") == 0){

return true;

}

case "à":
if (collator.compare(letra, "à") == 0){

return true;

}

case "â":
if (collator.compare(letra, "â") == 0){

return true;

}

case "ã":
if (collator.compare(letra, "ã") == 0){

return true;

}

case "é":
if (collator.compare(letra, "é") == 0){

return true;

}

case "è":
if (collator.compare(letra, "è") == 0){

return true;

}

case "ê":
if (collator.compare(letra, "ê") == 0){

return true;

}

case "&#7869;":
if (collator.compare(letra, "&#7869;") == 0){

return true;

}

case "í":
if (collator.compare(letra, "í") == 0){

return true;

}

case "ì":
if (collator.compare(letra, "ì") == 0){

return true;

}

case "ó":
if (collator.compare(letra, "ó") == 0){

return true;

}

case "ò":
if (collator.compare(letra, "ò") == 0){

return true;

}

case "ô":
if (collator.compare(letra, "ô") == 0){

return true;

}

case "õ":
if (collator.compare(letra, "õ") == 0){

return true;

}
case "ú":
if (collator.compare(letra, "ú") == 0){

return true;

}

case "ù":
if (collator.compare(letra, "ù") == 0){

return true;

}

}

return false;
}


public static boolean verificaVogal(char v) {

switch (v) {

case 'a':
return true;

case 'e':
return true;

case 'i':
return true;

case 'o':
return true;

case 'u':
return true;

}

return false;

}


public static String contaLetras(String frase) {

int vogal = 0, consoante = 0;


for (int cont = 0; cont < frase.length(); cont++) {

if (((frase.toLowerCase().charAt(cont) >= 'a') && (frase.toLowerCase().charAt(cont) <= 'z'))) {

if (verificaVogal(frase.toLowerCase().charAt(cont))) {

vogal++;

} else {

consoante++;

}
} else {

Character letra = frase.charAt(cont);
String l = letra.toString();

if (testeConsoante(l.toLowerCase())){

consoante++;

}

if (testeVogal(l.toLowerCase())){

vogal++;

}


}
}


return "Vogais: " + vogal + " Consoante: " + consoante;

}


public static void inicio() {

String frase, teste;
Scanner in = new Scanner(System.in);

do{
do {
System.out.println("Entre com a frase, por favor. Não utilize acentos e não ultrapasse o limite de 80 caracteres");
frase = in.nextLine();


if (frase.length() > 80) {

System.out.println("A frase contém mais que 80 caracteres. ");

}

} while (frase.length() > 80);

System.out.println(contaLetras(frase));

do {
System.out.println("Deseja fazer outro teste? [s/n]");
teste = in.nextLine();

if (teste.toLowerCase().equals("s") || teste.toLowerCase().equals("n")) {

if (teste.toLowerCase().equals("n")) {

System.out.println("Fim do programa...");

}


} else {

System.out.println("Informação Inválida! Digite apenas 's' ou 'n'.");

}
} while (!((teste.toLowerCase().equals("s")) || (teste.toLowerCase().equals("n"))));

} while(!(teste.toLowerCase().equals("n")));
}

public static void main(String[] args) {

inicio();

}

}





11. Re: Problema na comparação de caracteres com acento e ç/Ç [RESOLVIDO]

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 23/09/2012 - 20:28h

Ficou ótimo. Meus parabéns. Continue praticando.



  



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts