Dúvida em expressões regulares

Pessoa oque significa o matches ? Ele pega a String e verifica ela inteira ? E outra, oque significa o “*” em expressões regulares ? E a ultima dúvida, quando eu coloco apenas 1 nome ele entra no If, mas quando tem esse espaço e o segundo nome ele não entra, como eu resolvo a questão do espaço no primeiro if ?

    String nome_recebido = "Paula Luiza";
    
    if (nome_recebido.matches("[a-zA- 
    ZÁÂÃÀÇÉÊÍÓÔÕÚÜáâãàçéêíóôõúü]*")) {
        System.out.println("Só tem letras.");
    } 
    else if (nome_recebido.matches("[0-9]*")) {
        System.out.println("Só tem dígitos.");
    }

O método matches verifica se sua String casa com a regex passada por parâmetro.

Nenhuma, uma ou várias ocorrências.

1 curtida

matches verifica a string inteira. Então se ela tiver um único caractere que não corresponde à expressão, retorna false.

Os colchetes delimitam uma classe de caracteres, então [a-zA-ZÁÂÃÀÇÉÊÍÓÔÕÚÜáâãàçéêíóôõúü] procura por uma letra de “a” a “z” (indicado pelo intervalo a-z), ou uma letra de “A” a “Z” (A-Z), ou a letra “Á”, ou a letra “”, etc (qualquer uma delas serve).

Já o asterisco é um quantificador que significa “zero ou mais ocorrências”, portanto essa regex pega zero ou mais letras (qualquer uma das letras que estão dentro dos colchetes). Por isso que quando tem um espaço ela retorna false, pois a regex não diz que é para considerar espaços.

Vale lembrar também que, como o * significa “zero ou mais ocorrências”, então essa regex também retorna true se a string for vazia (""). Então se quer forçar que tenha pelo menos um caractere, pode trocá-lo para + (que significa “uma ou mais ocorrências”).

Para forçar que tenha um espaço, pode trocar para:

if (nome_recebido.matches("[a-zA-ZÁÂÃÀÇÉÊÍÓÔÕÚÜáâãàçéêíóôõúü]+( [a-zA-ZÁÂÃÀÇÉÊÍÓÔÕÚÜáâãàçéêíóôõúü]+)*")) {

Ou seja, primeiro tem uma ou mais letras. Depois tem um espaço seguido de uma ou mais letras, e todo este trecho (espaço + letras) pode se repetir zero ou mais vezes (repare que todo este trecho está entre parênteses e seguido do *, o que indica que “zero ou mais ocorrências” se aplica a tudo que está nos parênteses, que no caso é o “espaço + letras”).


Isso pode ser simplificado para:

if (nome_recebido.matches("\\p{IsLatin}+( \\p{IsLatin}+)*")) {

Agora usei o Unicode Property Escape \p{IsLatin}, que pega as letras do script Latin (o que inclui as letras acentuadas, tanto maiúsculas quanto minúsculas). A lógica é a mesma da anterior: uma ou mais letras, seguida de espaço + letras (e o trecho “espaço + letras” pode se repetir zero ou mais vezes).


Outro detalhe é que matches cria uma nova regex a cada execução, o que pode não parecer, mas é uma operação bem custosa (pois toda regex precisa ser compilada e possui um overhead que você não vê, mas está lá).

Se forem feitas muitas verificações, o melhor é compilar a expressão apenas uma vez e reusá-la. Para isso você pode usar estas classes:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

E o código ficaria assim:

// criar as regex apenas uma vez
Matcher letras = Pattern.compile("\\p{IsLatin}+( \\p{IsLatin}+)*").matcher("");
Matcher digitos = Pattern.compile("[0-9]+").matcher("");

// usar com uma string
String nomeRecebido = "Paula Luíza";
if (letras.reset(nomeRecebido).matches()) {
    System.out.println("Só tem letras.");
} else if (digitos.reset(nomeRecebido).matches()) {
    System.out.println("Só tem dígitos.");
}

// reaproveitar a regex com outra string
String outroNome = "Fulano de tal";
if (letras.reset(outroNome).matches()) {
    System.out.println("Só tem letras.");
} else if (digitos.reset(outroNome).matches()) {
    System.out.println("Só tem dígitos.");
}

Também mudei o nome da variável para ficar aderente às convenções de nomenclatura da linguagem, pois no Java há a preferência por nomesDesseJeito em vez de nomes_desse_jeito.

2 curtidas

Então deixa eu ver se eu entendi, ele vai pega a String inteira e verifica se ela possui os caracteres que estão sendo passados entre os colchetes ?

O “*” uma ou mais ocorrências, como assim ?
Qual a diferença de colocar ele ou não ?

No caso o “.reset” “formata” nomeRecebido nos padrões de letras ?

   if (letras.reset(nomeRecebido).matches()) {
   }

O * é “zero ou mais ocorrências”. O + é “uma ou mais ocorrências”.

É assim: [a-z] pega uma letra de “a” a “z” (somente uma). Mas se eu fizer [a-z]* aí ele pega zero ou mais ocorrências de letras de “a” a “z”. Ou seja pode ser zero letras (string vazia), uma letra, duas letras, 18994523 letras, etc, desde que todas sejam uma letra de “a” a “z”.

Se eu fizer [a-z]+, aí é “uma ou mais ocorrências” - é quase igual ao *, só que agora não aceita “zero letras”.

Já o reset é para resetar o Matcher, ou seja, para que ele faça a busca usando a string que você passar (se você não reseta, ele faz a busca na string que estava sendo usada anteriormente).

1 curtida

Entao se eu nao usar * ele vai pegar apenas 1 caracter de A - Z ?

Sim.

1 curtida

No caso de asterisco zero ou mais ocorrências, o zero seria tipo nenhum caracter ? Ou é tipo a String Paula por exemplo, “a” no caso tem mais ocorrências… E usando o asterisco os caracteres que Paula não possua são zero ocorrências ?

Sugiro que procure por aulas de expressões regulares, geralmente é ensinado na disciplina de linguagens formais.

Quando você tem um * significa que o que vem antes dele pode ocorrer nenhuma ou mais vezes na String.
Quando você tem um + significa que o que vem antes dele deve ocorrer pelo menos uma vez, mas pode ocorrer mais vezes na String.

Sim, quer dizer que o caractere não ocorre nenhuma vez.

Mas você tem que lembrar que matches verifica a string inteira. Então, por exemplo, se a regex for [a-z]* e você verificar a string vazia ("".matches("[a-z]*")), ela retorna true, porque a string vazia tem zero ocorrências de uma letra (a string vazia não tem “nada” (nenhum caractere), e portanto não tem nenhuma ocorrência da letra, por isso ela bate com o que a regex está buscando).

1 curtida

Se por exemplo eu não quero a String vazia então eu uso o + ?
Se eu quiser eu uso o asterisco ?
Se der certo e ela atender então retorna true senão false ?

Sim, mas tem que informar o conjunto de símbolos válidos antes do +.

Se você quer garantir que a String seja vazia, você verifica com o método isEmpty().

O * indica que se ela for vazia ela será válida, mas se ela tiver alguma coisa ela também será válida, onde o “alguma coisa” tem que bater com o conjunto de símbolos informados antes do *.

Ainda não leu a documentação?

1 curtida