JavaRush /Blogue Java /Random-PT /Expressões regulares em Java, Parte 3

Expressões regulares em Java, Parte 3

Publicado no grupo Random-PT
Apresentamos a sua atenção a tradução de um breve guia sobre expressões regulares em Java, escrito por Jeff Friesen para o site javaworld . Para facilitar a leitura, dividimos o artigo em várias partes. Expressões regulares em Java, Parte 3 - 1Expressões regulares em Java, parte 1 Expressões regulares em Java, parte 2

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 classe Patterne 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 Patterne Matcher. PatternSyntaxExceptionVocê 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

Patterne Matchersão PatternSyntaxExceptionas 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 classe Patterné 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údo regexem uma representação intermediária que é armazenada em um novo arquivo Pattern. Este método retorna uma referência a um objeto se for bem-sucedido ou lança uma exceção PatternSyntaxExceptionse uma sintaxe de expressão regular inválida for detectada. Qualquer objeto da classe Matcherusado Patternou 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ódigo Pattern p = Pattern.compile("(?m)^\\."); cria um objeto Patternque 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 que Pattern compile(String regex), mas levando em consideração flags: um conjunto de constantes de bits para sinalizadores de bits do tipo OR. A classe Patterndeclara constantes CANON_EQ, CASE_INSENSITIVE, COMMENTS, DOTALL, LITERAL, MULTILINE, UNICODE_CASE, UNICODE_CHARACTER_CLASS и UNIX_LINESque podem ser combinadas usando OR bit a bit (por exemplo, CASE_INSENSITIVE | DOTALL) e passadas como argumento flags.

  • 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.MULTILINEe a expressão de sinalizador aninhada (?m)fazendo a mesma coisa.
Às vezes é necessário obter uma cópia da string original de uma expressão regular compilada em um objeto 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 arquivo Pattern.

  • int flags()retorna os flags do objeto Pattern.
Depois de receber o objeto Pattern, ele normalmente é usado para obter o objeto Matcherpara realizar operações de correspondência de padrões. O método Matcher matcher(Charsequence input)cria um objeto Matcherque pesquisa no texto inputuma 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 Matcherpara o objeto Patternreferenciado pela variável p.
Pesquisa única
O método static boolean matches(String regex, CharSequence input)de classe Patternpermite economizar na criação de objetos Patterne Matcherna pesquisa única usando um modelo. Este método retorna verdadeiro se inputo 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 onlycontém apenas espaços e caracteres minúsculos.
Expressões regulares em Java, Parte 3 - 2

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 classe Patternoferece 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 divide textde acordo com as correspondências encontradas com o padrão do objeto Patterne 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 aparecem text.

    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-1correspondências e o comprimento da matriz não é maior do que limitelementos.
    • 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.

  • 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.
Abaixo estão os resultados do método 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, Patternum 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 ce 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 classe Matcherdescreve 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 Matchersuportam 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 na RegexDemoParte 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âmetro start. Se a pesquisa for bem-sucedida, o valor booleano true será retornado. Por exemplo, m.find(1);verifica o texto começando na posição 1(a posição 0 é ignorada). Se o parâmetro startcontiver um valor negativo ou um valor maior que o comprimento do texto correspondente, o método lançará uma exceção java.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ódigo Pattern p = Pattern.compile("\\w*"); Matcher m = p.matcher("abc!"); System.out.println(p.matches());é gerado falseporque 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étodo matches();, 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 texto abc!consiste apenas em caracteres formadores de palavras.

Ao contrário dos objetos de classe Pattern, os objetos de classe Matcherretê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 atual Matcher. Por exemplo, m.reset();redefine o resolvedor referenciado por m.

  • O método Matcher reset(CharSequence text)redefine o estado do resolvedor e define o novo texto do resolvedor como text. 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 atual Matcher. Por exemplo, m.reset("new text");redefine o resolvedor referenciado me define o novo texto do resolvedor como "new text".

Expressões regulares em Java, Parte 3 - 3

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 tipo java.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 objeto StringBufferreferenciado pelo argumento sb. 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 tipo Stringreferenciado pelo argumento replacementao final do objeto StringBuffer(a string replacementpode 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 Matcher appendReplacement(StringBuffer sb, String replacement)lança uma exceção java.lang.IllegalStateExceptionse o matcher ainda não encontrou uma correspondência ou se uma tentativa de pesquisa anterior falhou. Lança uma exceção IndexOutOfBoundsExceptionse a linha replacementespecificar um grupo de captura que não esteja no padrão).

  • O método StringBuffer appendTail(StringBuffer sb)adiciona todo o texto a um objeto StringBuffere retorna uma referência a esse objeto. Após a última chamada de método appendReplacement(StringBuffer sb, String replacement), chame o método appendTail(StringBuffer sb)para copiar o texto restante para o objeto StringBuffer.

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.
O código a seguir chama os métodos appendReplacement(StringBuffer sb, String replacement)e appendTail(StringBuffer sbpara substituir todas as ocorrências da sequência de caracteres no texto de origem catpor 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 erpillarapó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 classe Matchernos 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 objeto String, copia todos os caracteres do texto do matcher (até a primeira correspondência) para esta string, anexa os caracteres de até o final dela replacement, copia os caracteres restantes para a string e retorna um objeto String(a string replacementpode 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étodo String replaceFirst(String replacement), mas substitui replacementtodas as correspondências encontradas por caracteres da string.

Uma expressão regular \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
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION