Oper. ternário - número ou letra

pessoal,

com oper. ternário como faço pra saber se a string que entrou é número ou letra?

Consegui pensar nesta possibilidade:

import java.util.regex.Pattern;

public class App {
  private static String eNumeroOuLetra(String numeroOuLetra) {
    return Pattern.matches("[0-9]+", numeroOuLetra) ? "É número" : "É letra";
  }

  public static void main(String... args) {
    System.out.println(eNumeroOuLetra("abc"));
    System.out.println(eNumeroOuLetra("123"));
  }
}
1 curtida

obrigadaaa!

1 curtida

Outra forma:

  private static String eNumeroOuLetra(String numeroOuLetra) {
    return numeroOuLetra.matches("[0-9]+") ? "É número" : "É letra";
  }
2 curtidas

Na verdade é um pouco mais complicado que isso. As soluções acima verificam se só contém números, e se tiver qualquer coisa diferente disso, é considerado “letra”. Se a string for, por exemplo, "%^.", vai dizer que é letra. Se for "123a", também vai dizer que é letra - aliás, nesse caso faz o que?

Enfim, para tratar todos os casos, teria que fazer um pouco diferente (inclusive, “forçar” o uso de operador ternário nem me parece a melhor opção, mas enfim).

Uma opção é ver o primeiro caractere: se for número, eu vejo se o restante é número. Se for letra, eu vejo se o restante é letra. Se não for nem número nem letra, nem preciso ver o resto. E se no meio eu encontro um caractere que não é do mesmo tipo do primeiro, também não preciso ver o resto:

private static String somenteNumerosOuLetras(String str) {
    if (str.length() == 0) { // string vazia, nem preciso ver
        return "Não tem somente números nem somente letras";
    }

    char primeiro = str.charAt(0);
    Predicate<Character> condicao = null;
    String retorno = null;
    if (Character.isDigit(primeiro)) { // se o primeiro é número, eu testo se os demais são números
        condicao = Character::isDigit;
        retorno = "somente dígitos";
    } else if (Character.isLetter(primeiro)) { // se o primeiro é letra, eu testo se os demais são letras
        condicao = Character::isLetter;
        retorno = "somente letras";
    }

    // se o primeiro não é número nem letra, posso parar aqui
    if (condicao == null) {
        return "Não tem somente números nem somente letras";
    }

    // percorro do segundo caractere em diante, vendo se são do mesmo tipo do primeiro
    for (int i = 1; i < str.length(); i++) {
        char c = str.charAt(i);
        if (! condicao.test(c)) { // não é do mesmo tipo, pode retornar (nem preciso ver o resto)
            return "Não tem somente números nem somente letras";
        }
    }
    // se chegou aqui é porque todos os caracteres são do mesmo tipo
    return retorno;
}

Testando:

System.out.println(somenteNumerosOuLetras("123"));    // somente dígitos
System.out.println(somenteNumerosOuLetras("abc"));    // somente letras
System.out.println(somenteNumerosOuLetras("123abc")); // Não tem somente números nem somente letras
System.out.println(somenteNumerosOuLetras("@#$%"));   // Não tem somente números nem somente letras

Claro que o código ficou “maior”, mas não necessariamente isso é pior. Usar regex, apesar de deixar o código mais curto, é mais lento (claro que para poucas strings pequenas a diferença é imperceptível, mas para grandes quantidades e/ou strings maiores isso pode começar a fazer diferença).

De qualquer forma, como agora são duas condições, com regex teria que fazer dois ternários aninhados:

private static String somenteNumerosOuLetras(String str) {
    return str.matches("[0-9]+")
           ? "somente dígitos"
           : ( str.matches("[a-zA-Z]+")
               ? "somente letras"
               : "Não tem somente números nem somente letras" );
}

Um detalhe é que [a-zA-Z]+ não aceita letras acentuadas, mas se quiser pode trocar para str.matches("\\p{L}+"), que pega qualquer letra definida pelo Unicode (incluindo outros alfabetos, como árabe, japonês, cirílico, etc). Ou ainda str.matches("\\p{IsLatin}+"), se quiser apenas as letras do nosso alfabeto. Já o primeiro código não precisa de modificação, pois Character.isLetter já considera qualquer letra Unicode.

Vale lembrar também que cada regex percorre a string uma vez, portanto no pior caso ela será percorrida duas vezes. E novamente, para poucas strings pequenas não faz diferença, mas é importante saber as implicações de cada linha de código que você escreve, e não escolher algo somente porque “é mais curto”.

4 curtidas

Será que essa forma também seria válida?

public class Main {
	
	public static void main(String[] args) throws Exception {
		System.out.println(check("aaa"));
		System.out.println(check("123"));
		System.out.println(check("a2c"));
		System.out.println(check("!@#"));
		System.out.println(check("-+."));
		System.out.println(check("-10"));
		System.out.println(check("000"));
	}
	
	private static String check(String texto) {
		boolean isLetras = texto.codePoints()
			.allMatch(c -> (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
		
		boolean isNumeros = texto.codePoints()
			.allMatch(c -> c >= '0' && c <= '9');

		return (isLetras) ? "são letras" : (isNumeros) ? "são números" : "nem tudo letra nem tudo número";
	}
}
1 curtida