O que é uma expressão regular (regex)?
Na verdade, uma expressão regular é um padrão para encontrar uma string no texto. Em Java, a representação original desse padrão é sempre uma string, ou seja, um objeto daStringclasse. No entanto, não é qualquer string que pode ser compilada em uma expressão regular — apenas strings que obedecem às regras de criação de expressões regulares. A sintaxe é definida na especificação da linguagem. As expressões regulares são escritas usando letras e números, bem como metacaracteres, que são caracteres que têm um significado especial na sintaxe da expressão regular. Por exemplo:
String regex = "java"; // The pattern is "java";
String regex = "\\d{3}"; // The pattern is three digits;
Criando expressões regulares em Java
A criação de uma expressão regular em Java envolve duas etapas simples:- escrevê-lo como uma string que esteja em conformidade com a sintaxe de expressão regular;
- compilar a string em uma expressão regular;
Patternobjeto. Para fazer isso, precisamos chamar um dos dois métodos estáticos da classe: compile. O primeiro método usa um argumento — uma string literal contendo a expressão regular, enquanto o segundo usa um argumento adicional que determina as configurações de correspondência de padrão:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
A lista de valores potenciais do flagsparâmetro é definida na Patternclasse e está disponível para nós como variáveis de classe estáticas. Por exemplo:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE); // Pattern-matching will be case insensitive.
Basicamente, a Patternclasse é um construtor de expressões regulares. Nos bastidores, o compilemétodo chama o Patternconstrutor privado da classe para criar uma representação compilada. Esse mecanismo de criação de objetos é implementado dessa maneira para criar objetos imutáveis. Quando uma expressão regular é criada, sua sintaxe é verificada. Se a string contiver erros, um PatternSyntaxExceptionserá gerado.
Sintaxe de expressão regular
A sintaxe da expressão regular depende dos<([{\^-=$!|]})?*+.>caracteres, que podem ser combinados com letras. Dependendo de sua função, eles podem ser divididos em vários grupos:
| Metacaractere | Descrição |
|---|---|
| ^ | início de uma linha |
| $ | fim de uma linha |
| \b | limite de palavras |
| \B | fronteira não-palavra |
| \A | início da entrada |
| \G | final da partida anterior |
| \Z | fim da entrada |
| \z | fim da entrada |
| Metacaractere | Descrição |
|---|---|
| \d | dígito |
| \D | não dígito |
| \s | caractere de espaço em branco |
| \S | caractere sem espaço em branco |
| \c | caractere alfanumérico ou sublinhado |
| \C | qualquer caractere, exceto letras, números e sublinhado |
| . | qualquer personagem |
| Metacaractere | Descrição |
|---|---|
| \t | caractere de tabulação |
| \n | caractere de nova linha |
| \r | retorno de carruagem |
| \f | caractere de avanço de linha |
| \u0085 | caractere da próxima linha |
| \u2028 | separador de linha |
| \u2029 | separador de parágrafo |
| Metacaractere | Descrição |
|---|---|
| [abc] | qualquer um dos caracteres listados (a, b ou c) |
| [^abc] | qualquer caractere diferente dos listados (não a, b ou c) |
| [a-zA-Z] | intervalos mesclados (caracteres latinos de a a z, sem distinção entre maiúsculas e minúsculas) |
| [anúncio[mp]] | união de caracteres (de a a d e de m a p) |
| [az&&[def]] | interseção de caracteres (d, e, f) |
| [az&&[^bc]] | subtração de caracteres (a, dz) |
| Metacaractere | Descrição |
|---|---|
| ? | um ou nenhum |
| * | zero ou mais vezes |
| + | uma ou mais vezes |
| {n} | n vezes |
| {n,} | n ou mais vezes |
| {n,m} | pelo menos n vezes e não mais que m vezes |
quantificadores gananciosos
Uma coisa que você deve saber sobre quantificadores é que eles vêm em três variedades diferentes: gananciosos, possessivos e relutantes. Você torna um quantificador possessivo adicionando um+caractere " " após o quantificador. Você o torna relutante adicionando " ?". Por exemplo:
"A.+a" // greedy
"A.++a" // possessive
"A.+?a" // reluctant
Vamos tentar usar esse padrão para entender como funcionam os diferentes tipos de quantificadores. Por padrão, os quantificadores são gananciosos. Isso significa que eles procuram a correspondência mais longa na string. Se executarmos o seguinte código:
public static void main(String[] args) {
String text = "Fred Anna Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
obtemos esta saída:
Anna Alexa
Para a expressão regular " A.+a", a correspondência de padrões é executada da seguinte forma:
-
O primeiro caractere no padrão especificado é a letra latina
A.Matchercompara-o com cada caractere do texto, começando do índice zero. O caractereFestá no índice zero em nosso texto, portantoMatcheritera pelos caracteres até que corresponda ao padrão. Em nosso exemplo, esse caractere é encontrado no índice 5.![Expressões regulares em Java - 2]()
-
Uma vez encontrada uma correspondência com o primeiro caractere do padrão,
Matcherprocura uma correspondência com seu segundo caractere. No nosso caso, é o.caractere " ", que representa qualquer caractere.
O personagem
nestá na sexta posição. Certamente se qualifica como uma correspondência para "qualquer personagem". -
Matcherprossegue para verificar o próximo caractere do padrão. Em nosso padrão, ele está incluído no quantificador que se aplica ao caractere precedente: ".+". Como o número de repetições de "qualquer caractere" em nosso padrão é uma ou mais vezes,Matcherrepetidamente pega o próximo caractere da string e o compara com o padrão, desde que corresponda a "qualquer caractere". Em nosso exemplo — até o final da string (do índice 7 ao índice 18).
Basicamente,
Matcherengole a string até o fim - é exatamente isso que significa "ganancioso". -
Após o Matcher atingir o final do texto e concluir a verificação da
A.+parte " " do padrão, ele começa a verificar o restante do padrão:a. Não há mais texto avançando, então a verificação prossegue "recuando", começando pelo último caractere:![Expressões regulares em Java - 5]()
-
Matcher"lembra" o número de repetições na.+parte " " do padrão. Nesse ponto, ele reduz o número de repetições em um e verifica o padrão maior no texto até encontrar uma correspondência:![Expressões regulares em Java - 6]()
quantificadores possessivos
Os quantificadores possessivos são muito parecidos com os gulosos. A diferença é que quando o texto foi capturado até o final da string, não há correspondência de padrão durante o "recuo". Em outras palavras, os três primeiros estágios são os mesmos dos quantificadores gulosos. Depois de capturar a string inteira, o matcher adiciona o restante do padrão ao que está considerando e o compara com a string capturada. Em nosso exemplo, usando a expressão regular "A.++a", o método main não encontra nenhuma correspondência.
quantificadores relutantes
-
Para esses quantificadores, assim como para a variedade gananciosa, o código procura uma correspondência com base no primeiro caractere do padrão:
![Expressões regulares em Java - 8]()
-
Em seguida, ele procura uma correspondência com o próximo caractere do padrão (qualquer caractere):
![Expressões regulares em Java - 9]()
-
Ao contrário da correspondência de padrão gulosa, a correspondência mais curta é procurada na correspondência de padrão relutante. Isso significa que após encontrar uma correspondência com o segundo caractere do padrão (um ponto, que corresponde ao caractere na posição 6 no texto,
Matcherverifica se o texto corresponde ao restante do padrão — o caractere "a"![Expressões regulares em Java - 10]()
-
O texto não corresponde ao padrão (ou seja, contém o caractere "
n" no índice 7), entãoMatcheradiciona mais um "qualquer caractere", porque o quantificador indica um ou mais. Em seguida, compara novamente o padrão com o texto nas posições 5 a 8:![Expressões regulares em Java - 11]()
No nosso caso, foi encontrada uma correspondência, mas ainda não chegamos ao final do texto. Portanto, o pattern-matching recomeça a partir da posição 9, ou seja, o primeiro caractere do pattern é procurado por meio de um algoritmo semelhante e isso se repete até o final do texto.
mainmétodo obtém o seguinte resultado ao usar o padrão " A.+?a": Anna Alexa Como você pode ver em nosso exemplo, diferentes tipos de quantificadores produzem resultados diferentes para o mesmo padrão. Portanto, tenha isso em mente e escolha a variedade certa com base no que você está procurando.
Caracteres de escape em expressões regulares
Como uma expressão regular em Java, ou melhor, sua representação original, é uma string literal, precisamos levar em consideração as regras de Java relacionadas a strings literais. Em particular, o caractere de barra invertida "\" em strings literais no código-fonte Java é interpretado como um caractere de controle que informa ao compilador que o próximo caractere é especial e deve ser interpretado de maneira especial. Por exemplo:
String s = "The root directory is \nWindows"; // Move "Windows" to a new line
String s = "The root directory is \u00A7Windows"; // Insert a paragraph symbol before "Windows"
Isso significa que strings literais que descrevem expressões regulares e usam \caracteres " " (ou seja, para indicar metacaracteres) devem repetir as barras invertidas para garantir que o compilador de bytecode Java não interprete mal a string. Por exemplo:
String regex = "\\s"; // Pattern for matching a whitespace character
String regex = "\"Windows\""; // Pattern for matching "Windows"
Barras invertidas duplas também devem ser usadas para escapar de caracteres especiais que queremos usar como caracteres "normais". Por exemplo:
String regex = "How\\?"; // Pattern for matching "How?"
Métodos da classe Pattern
APatternclasse tem outros métodos para trabalhar com expressões regulares:
-
String pattern()‒ retorna a representação de string original da expressão regular usada para criar oPatternobjeto:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.pattern()); // "abc" -
static boolean matches(String regex, CharSequence input)– permite verificar a expressão regular passada como regex em relação ao texto passado comoinput. Retorna:true – se o texto corresponder ao padrão;
falso – se não;Por exemplo:
System.out.println(Pattern.matches("A.+a","Anna")); // true System.out.println(Pattern.matches("A.+a","Fred Anna Alexander")); // false -
int flags()‒ retorna o valor doflagsparâmetro do padrão definido quando o padrão foi criado ou 0 se o parâmetro não foi definido. Por exemplo:Pattern pattern = Pattern.compile("abc"); System.out.println(pattern.flags()); // 0 Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE); System.out.println(pattern.flags()); // 2 -
String[] split(CharSequence text, int limit)– divide o texto passado em umaStringmatriz. Olimitparâmetro indica o número máximo de correspondências pesquisadas no texto:- se
limit > 0‒limit-1corresponder; - if
limit < 0‒ todas as correspondências no texto - se
limit = 0‒ todas as correspondências no texto, strings vazias no final do array são descartadas;
Por exemplo:
public static void main(String[] args) { String text = "Fred Anna Alexa"; Pattern pattern = Pattern.compile("\\s"); String[] strings = pattern.split(text,2); for (String s : strings) { System.out.println(s); } System.out.println("---------"); String[] strings1 = pattern.split(text); for (String s : strings1) { System.out.println(s); } }Saída do console:
Fred Anna Alexa --------- Fred Anna AlexaA seguir, consideraremos outro método da classe usado para criar um
Matcherobjeto. - se
Métodos da classe Matcher
As instâncias daMatcherclasse são criadas para realizar a correspondência de padrões. Matcheré o "mecanismo de busca" para expressões regulares. Para realizar uma pesquisa, precisamos fornecer duas coisas: um padrão e um índice inicial. Para criar um Matcherobjeto, a Patternclasse fornece o seguinte método: рublic Matcher matcher(CharSequence input) O método recebe uma sequência de caracteres, que será pesquisada. Esta é uma instância de uma classe que implementa a CharSequenceinterface. Você pode passar não apenas a String, mas também a StringBuffer, StringBuilder, Segmentou CharBuffer. O padrão é um Patternobjeto no qual o matchermétodo é chamado. Exemplo de criação de um correspondente:
Pattern p = Pattern.compile("a*b"); // Create a compiled representation of the regular expression
Matcher m = p.matcher("aaaaab"); // Create a "search engine" to search the text "aaaaab" for the pattern "a*b"
Agora podemos usar nosso "mecanismo de busca" para procurar correspondências, obter a posição de uma correspondência no texto e substituir o texto usando os métodos da classe. O boolean find()método procura a próxima correspondência no texto. Podemos usar esse método e uma instrução de loop para analisar um texto inteiro como parte de um modelo de evento. Em outras palavras, podemos realizar as operações necessárias quando ocorre um evento, ou seja, quando encontramos uma correspondência no texto. Por exemplo, podemos usar os métodos int start()e dessa classe int end()para determinar a posição de uma correspondência no texto. E podemos usar os métodos String replaceFirst(String replacement)e String replaceAll(String replacement)para substituir correspondências pelo valor do parâmetro de substituição. Por exemplo:
public static void main(String[] args) {
String text = "Fred Anna Alexa";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found: " + text.substring(start, end) + " from index "+ start + " through " + (end-1));
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Mary"));
System.out.println(text);
}
Saída:
Match found: Anna from index 5 through 8
Match found: Alexa from index 10 through 14
Fred Ira Alexa
Fred Mary Mary
Fred Anna Alexa
O exemplo deixa claro que os métodos replaceFirste replaceAllcriam um novo Stringobjeto — uma string na qual correspondências de padrão no texto original são substituídas pelo texto passado para o método como um argumento. Além disso, o replaceFirstmétodo substitui apenas a primeira correspondência, mas o replaceAllmétodo substitui todas as correspondências no texto. O texto original permanece inalterado. As operações regex mais frequentes das classes Patterne Matchersão construídas diretamente na Stringclasse. Esses são métodos como split, matches, replaceFirste replaceAll. Mas sob o capô, esses métodos usam as classes Patterne Matcher. Portanto, se você deseja substituir texto ou comparar strings em um programa sem escrever nenhum código extra, use os métodos doStringaula. Se você precisar de recursos mais avançados, lembre-se das classes Patterne Matcher.
Conclusão
Em um programa Java, uma expressão regular é definida por uma cadeia de caracteres que obedece a regras específicas de correspondência de padrões. Ao executar o código, a máquina Java compila essa string em umPatternobjeto e usa um Matcherobjeto para localizar correspondências no texto. Como eu disse no início, as pessoas costumam deixar as expressões regulares para depois, por considerá-las um assunto difícil. Mas se você entender a sintaxe básica, os metacaracteres e o escape de caracteres e estudar exemplos de expressões regulares, descobrirá que eles são muito mais simples do que parecem à primeira vista.
|
Mais leitura: |
|---|







GO TO FULL VERSION