Simplifique tarefas comuns de programação com a API Regex
Nas partes 1 e 2 deste artigo, você conheceu expressões regulares e a API Regex. Você aprendeu sobre a classePattern
e percorreu exemplos que demonstram construções de expressões regulares, desde correspondência simples de padrões usando strings literais até correspondências mais complexas usando intervalos, correspondências de limite e quantificadores. Nesta e nas partes subsequentes consideraremos questões não abordadas na primeira parte, estudaremos os métodos correspondentes das classes Pattern
e Matcher
. PatternSyntaxException
Você também aprenderá dois utilitários que usam expressões regulares para facilitar problemas comuns de programação. O primeiro extrai comentários do código para documentação. A segunda é uma biblioteca de código reutilizável projetada para realizar análises lexicais – um componente essencial de montadores, compiladores e softwares similares.
BAIXANDO CÓDIGO FONTE
Você pode obter todo o código-fonte (criado por Jeff Friesen para JavaWorld) para os aplicativos de demonstração neste artigo aqui .Aprendendo a API Regex
Pattern
e Matcher
são PatternSyntaxException
as três classes que compõem a API Regex. Cada um deles fornece métodos que permitem usar expressões regulares em seu código.
Métodos da classe Pattern
Uma instância de uma classePattern
é uma expressão regular compilada, também conhecida como padrão. Expressões regulares são compiladas para melhorar o desempenho das operações de correspondência de padrões. Os métodos estáticos a seguir oferecem suporte à compilação.
Pattern compile(String regex)
compila o conteúdoregex
em uma representação intermediária que é armazenada em um novo arquivoPattern
. Este método retorna uma referência a um objeto se for bem-sucedido ou lança uma exceçãoPatternSyntaxException
se uma sintaxe de expressão regular inválida for detectada. Qualquer objeto da classeMatcher
usadoPattern
ou retornado por esse objeto usa suas configurações padrão, como pesquisa com distinção entre maiúsculas e minúsculas. Por exemplo, o trecho de códigoPattern p = Pattern.compile("(?m)^\\.");
cria um objetoPattern
que armazena uma representação compilada de uma expressão regular para corresponder a strings que começam com um caractere de ponto.Pattern compile(String regex, int flags)
resolve o mesmo problema quePattern compile(String regex)
, mas levando em consideraçãoflags
: um conjunto de constantes de bits para sinalizadores de bits do tipo OR. A classePattern
declara constantesCANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINES
que podem ser combinadas usando OR bit a bit (por exemplo,CASE_INSENSITIVE | DOTALL
) e passadas como argumentoflags
.
Com exceção de
CANON_EQ, LITERAL и UNICODE_CHARACTER_CLASS
, essas constantes são uma alternativa às expressões de sinalização aninhadas demonstradas na Parte 1. Se uma constante de sinalização diferente daquelas definidas na classe for encontrada Pattern
, o método Pattern compile(String regex, int flags)
lança uma exceção java.lang.IllegalArgumentException
. Por exemplo, Pattern p = Pattern.compile("^\\.", Pattern.MULTILINE);
equivalente ao exemplo anterior, com a constante Pattern.MULTILINE
e a expressão de sinalizador aninhada (?m)
fazendo a mesma coisa.
Pattern
, junto com os sinalizadores que ela utiliza. Para fazer isso, você pode chamar os seguintes métodos:
String pattern()
retorna a string de expressão regular original compilada em um arquivoPattern
.int flags()
retorna os flags do objetoPattern
.
Pattern
, ele normalmente é usado para obter o objeto Matcher
para realizar operações de correspondência de padrões. O método Matcher matcher(Charsequence input)
cria um objeto Matcher
que pesquisa no texto input
uma correspondência com um padrão de objeto Pattern
. Quando chamado, retorna uma referência a este objeto Matcher
. Por exemplo, o comando Matcher m = p.matcher(args[1]);
retorna Matcher
para o objeto Pattern
referenciado pela variável p
.
Pesquisa única |
---|
O método static boolean matches(String regex, CharSequence input) de classe Pattern permite economizar na criação de objetos Pattern e Matcher na pesquisa única usando um modelo. Este método retorna verdadeiro se input o padrão for correspondido regex , caso contrário, retorna falso. Se a expressão regular contiver um erro de sintaxe, o método lançará uma exceção PatternSyntaxException . Por exemplo, System.out.println(Pattern.matches("[a-z[\\s]]*", "all lowercase letters and whitespace only")); imprime true , confirmando que a frase all lowercase letters and whitespace only contém apenas espaços e caracteres minúsculos. |
Dividindo texto
A maioria dos desenvolvedores escreveu pelo menos uma vez código para dividir o texto de entrada em suas partes componentes, como converter uma conta de funcionário baseada em texto em um conjunto de campos. A classePattern
oferece a capacidade de resolver de forma mais conveniente essa tarefa tediosa usando dois métodos de divisão de texto:
-
O método
String[] split(CharSequence text, int limit)
se dividetext
de acordo com as correspondências encontradas com o padrão do objetoPattern
e retorna os resultados em um array. Cada elemento da matriz especifica uma sequência de texto separada da próxima sequência por um fragmento de texto correspondente ao padrão (ou final do texto). Os elementos do array estão na mesma ordem em que aparecemtext
.Neste método, o número de elementos do array depende do parâmetro
limit
, que também controla o número de correspondências a serem encontradas.- Um valor positivo não procura mais do que
limit-1
correspondências e o comprimento da matriz não é maior do quelimit
elementos. - Se o valor for negativo, todas as correspondências possíveis serão pesquisadas e o comprimento da matriz poderá ser arbitrário.
- Se o valor for zero, todas as correspondências possíveis serão pesquisadas, o comprimento do array poderá ser arbitrário e as linhas vazias no final serão descartadas.
- Um valor positivo não procura mais do que
- O método
String[] split(CharSequence text)
chama o método anterior com 0 como argumento de limite e retorna o resultado de sua chamada.
split(CharSequence text)
para resolver o problema de divisão da conta de um funcionário em campos separados de nome, idade, endereço postal e salário:
Pattern p = Pattern.compile(",\\s");
String[] fields = p.split("John Doe, 47, Hillsboro Road, 32000");
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i]);
O código acima descreve uma expressão regular para localizar um caractere de vírgula imediatamente seguido por um único caractere de espaço. Aqui estão os resultados de sua execução:
John Doe
47
Hillsboro Road
32000
Predicados de modelo e API Streams
No Java 8,Pattern
um método apareceu na classe . Este método cria um predicado (uma função com um valor booleano) que é usado para corresponder ao padrão. O uso deste método é mostrado no seguinte trecho de código: Predicate
asPredicate()
List progLangs = Arrays.asList("apl", "basic", "c", "c++", "c#", "cobol", "java", "javascript", "perl", "python", "scala");
Pattern p = Pattern.compile("^c");
progLangs.stream().filter(p.asPredicate()).forEach(System.out::println);
Este código cria uma lista de nomes de linguagens de programação e, em seguida, compila um padrão para encontrar todos os nomes que começam com a letra c
. A última linha de código acima implementa o recebimento de um fluxo serial de dados com esta lista como fonte. Ele configura um filtro usando uma função booleana asPredicate()
que retorna true quando o nome começa com uma letra c
e itera pelo fluxo, imprimindo nomes correspondentes na saída padrão. Esta última linha é equivalente ao seguinte loop regular, familiar do aplicativo RegexDemo da Parte 1:
for (String progLang: progLangs)
if (p.matcher(progLang).find())
System.out.println(progLang);
Métodos de classe correspondente
Uma instância da classeMatcher
descreve um mecanismo para realizar operações de correspondência de padrões em uma sequência de caracteres, interpretando a expressão regular compilada da classe Pattern
. Os objetos da classe Matcher
suportam vários tipos de operações de pesquisa de padrões:
-
O método
boolean find()
pesquisa o texto de entrada para a próxima correspondência. Este método começa a digitalização no início do texto especificado ou no primeiro caractere após a correspondência anterior. A segunda opção só é possível se a chamada anterior para este método retornar verdadeiro e o resolvedor não tiver sido redefinido. Em qualquer caso, se a pesquisa for bem-sucedida, o valor booleano true será retornado. Um exemplo deste método pode ser encontrado naRegexDemo
Parte 1. -
O método
boolean find(int start)
redefine o matcher e procura no texto a próxima correspondência. A visualização começa na posição especificada pelo parâmetrostart
. Se a pesquisa for bem-sucedida, o valor booleano true será retornado. Por exemplo,m.find(1);
verifica o texto começando na posição1
(a posição 0 é ignorada). Se o parâmetrostart
contiver um valor negativo ou um valor maior que o comprimento do texto correspondente, o método lançará uma exceçãojava.lang.IndexOutOfBoundsException
. -
O método
boolean matches()
tenta combinar todo o texto com um padrão. Ele retorna um valor booleano verdadeiro se todo o texto corresponder ao padrão. Por exemplo, o códigoPattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());
é geradofalse
porque o caractere!
não é um caractere de palavra. -
O método
boolean lookingAt()
tenta combinar o texto especificado com o padrão. Este método retorna verdadeiro se alguma parte do texto corresponder ao padrão. Ao contrário do métodomatches();
, todo o texto não precisa corresponder ao padrão. Por exemplo,Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.lookingAt());
a saída serátrue
, já que o início do textoabc!
consiste apenas em caracteres formadores de palavras.
Pattern
, os objetos de classe Matcher
retêm informações de estado. Às vezes, pode ser necessário redefinir o matcher para limpar essas informações após a conclusão da pesquisa de padrão. Os seguintes métodos estão disponíveis para redefinir o resolvedor:
-
O método
Matcher reset()
redefine o estado do matcher, incluindo a posição a ser anexada ao final (redefinida para 0). A próxima operação de pesquisa de padrão começa no início do texto correspondente. Retorna uma referência ao objeto atualMatcher
. Por exemplo,m.reset();
redefine o resolvedor referenciado porm
. -
O método
Matcher reset(CharSequence text)
redefine o estado do resolvedor e define o novo texto do resolvedor comotext
. A próxima operação de pesquisa de padrão começa no início do novo texto correspondente. Retorna uma referência ao objeto atualMatcher
. Por exemplo,m.reset("new text");
redefine o resolvedor referenciadom
e define o novo texto do resolvedor como"new text"
.
Adicionando texto ao final
A posição do correspondente a ser anexado ao final especifica o início do texto do correspondente que é anexado ao final do objeto do tipojava.lang.StringBuffer
. Os seguintes métodos usam esta posição:
-
O método
Matcher appendReplacement(StringBuffer sb, String replacement)
lê os caracteres de texto correspondentes e os anexa ao final do objetoStringBuffer
referenciado pelo argumentosb
. Este método interrompe a leitura no último caractere anterior à correspondência de padrão anterior. Em seguida, o método anexa os caracteres do objeto do tipoString
referenciado pelo argumentoreplacement
ao final do objetoStringBuffer
(a stringreplacement
pode conter referências a sequências de texto capturadas durante a pesquisa anterior; estas são especificadas usando os caracteres($)
e números de grupo que estão sendo capturados). Finalmente, o método define o valor da posição do correspondente para anexar à posição do último caractere correspondente mais um e, em seguida, retorna uma referência ao correspondente atual. -
O método
StringBuffer appendTail(StringBuffer sb)
adiciona todo o texto a um objetoStringBuffer
e retorna uma referência a esse objeto. Após a última chamada de métodoappendReplacement(StringBuffer sb, String replacement)
, chame o métodoappendTail(StringBuffer sb)
para copiar o texto restante para o objetoStringBuffer
.
O método Matcher appendReplacement(StringBuffer sb, String replacement)
lança uma exceção java.lang.IllegalStateException
se o matcher ainda não encontrou uma correspondência ou se uma tentativa de pesquisa anterior falhou. Lança uma exceção IndexOutOfBoundsException
se a linha replacement
especificar um grupo de captura que não esteja no padrão).
Grupos capturados |
---|
Como você se lembra da Parte 1, um grupo de captura é uma sequência de caracteres entre parênteses ( () ) metacaracteres. O objetivo desta construção é armazenar os caracteres encontrados para reutilização posterior durante a correspondência de padrões. Todos os caracteres do grupo capturado são considerados como um todo durante a busca de padrões. |
appendReplacement(StringBuffer sb, String replacement)
e appendTail(StringBuffer sb
para substituir todas as ocorrências da sequência de caracteres no texto de origem cat
por caterpillar
:
Pattern p = Pattern.compile("(cat)");
Matcher m = p.matcher("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer();
while (m.find())
m.appendReplacement(sb, "$1erpillar");
m.appendTail(sb);
System.out.println(sb);
Usar um grupo capturado e uma referência a ele no texto de substituição informa ao programa para inserir erpillar
após cada ocorrência de cat
. O resultado da execução deste código é assim: one caterpillar, two caterpillars, or three caterpillars on a fence
Substituindo texto
A classeMatcher
nos fornece dois métodos para substituição de texto, complementares ao appendReplacement(StringBuffer sb, String replacement)
. Usando esses métodos, você pode substituir a primeira ocorrência do [texto substituído] ou todas as ocorrências:
-
O método
String replaceFirst(String replacement)
redefine o matcher, cria um novo objetoString
, copia todos os caracteres do texto do matcher (até a primeira correspondência) para esta string, anexa os caracteres de até o final delareplacement
, copia os caracteres restantes para a string e retorna um objetoString
(a stringreplacement
pode conter referências àqueles capturados durante as sequências de texto de pesquisa anteriores usando símbolos de cifrão e números de grupo capturados). -
O método
String replaceAll(String replacement)
opera de forma semelhante ao métodoString replaceFirst(String replacement)
, mas substituireplacement
todas as correspondências encontradas por caracteres da string.
\s+
procura um ou mais caracteres de espaço em branco no texto de entrada. Abaixo, usaremos esta expressão regular e chamaremos um método replaceAll(String replacement)
para remover espaços duplicados:
Pattern p = Pattern.compile("\\s+");
Matcher m = p.matcher("Удаляем \t\t лишние пробелы. ");
System.out.println(m.replaceAll(" "));
Aqui estão os resultados: Удаляем лишние пробелы.
Expressões regulares em Java, Parte 4 Expressões regulares em Java, Parte 5
GO TO FULL VERSION