Grupos nomeados Regex em Java

173

Entendo que o java.regexpacote não tem suporte para grupos nomeados ( http://www.regular-expressions.info/named.html ), então alguém pode me indicar uma biblioteca de terceiros que possui?

Eu olhei para o jregex, mas seu último lançamento foi em 2002 e não funcionou para mim (na verdade eu tentei apenas brevemente) no java5.

Dan
fonte
3
Sua compreensão está incorreta. O JDK7 manipula grupos nomeados.
tchrist
2
@tchrist Em 2009 não havia JDK7.
precisa saber é o seguinte

Respostas:

275

( Atualização : agosto de 2011 )

Como geofflane menciona em sua resposta , o Java 7 agora suporta grupos nomeados .
tchrist aponta no comentário que o suporte é limitado.
Ele detalha as limitações em sua ótima resposta " Java Regex Helper "

O regex Java 7 chamado suporte ao grupo foi apresentado em setembro de 2010 no blog da Oracle .

No release oficial do Java 7, as construções para suportar o grupo de captura nomeado são:

  • (?<name>capturing text) definir um grupo nomeado "nome"
  • \k<name> voltar a referenciar um grupo nomeado "nome"
  • ${name} para referenciar o grupo capturado na sequência de substituição do Matcher
  • Matcher.group(String name) para retornar a subsequência de entrada capturada pelo "grupo nomeado" especificado.

Outras alternativas para o pré-Java 7 foram:


( Resposta original : janeiro de 2009 , com os próximos dois links agora quebrados)

Você não pode se referir ao grupo nomeado, a menos que codifique sua própria versão do Regex ...

Foi exatamente isso que Gorbush2 fez neste tópico .

Regex2

(implementação limitada, como apontado novamente por tchrist , pois procura apenas identificadores ASCII. tchrist detalha a limitação como:

apenas poder ter um grupo nomeado por mesmo nome (que você nem sempre tem controle!) e não poder usá-los para recursão dentro da regex.

Nota: Você pode encontrar exemplos reais de recursão de regex em regexes Perl e PCRE, conforme mencionado no Regexp Power , especificações de PCRE e correspondência de strings com parênteses balanceados )

Exemplo:

Corda:

"TEST 123"

RegExp:

"(?<login>\\w+) (?<id>\\d+)"

Acesso

matcher.group(1) ==> TEST
matcher.group("login") ==> TEST
matcher.name(1) ==> login

Substituir

matcher.replaceAll("aaaaa_$1_sssss_$2____") ==> aaaaa_TEST_sssss_123____
matcher.replaceAll("aaaaa_${login}_sssss_${id}____") ==> aaaaa_TEST_sssss_123____ 

(extrato da implementação)

public final class Pattern
    implements java.io.Serializable
{
[...]
    /**
     * Parses a group and returns the head node of a set of nodes that process
     * the group. Sometimes a double return system is used where the tail is
     * returned in root.
     */
    private Node group0() {
        boolean capturingGroup = false;
        Node head = null;
        Node tail = null;
        int save = flags;
        root = null;
        int ch = next();
        if (ch == '?') {
            ch = skip();
            switch (ch) {

            case '<':   // (?<xxx)  look behind or group name
                ch = read();
                int start = cursor;
[...]
                // test forGroupName
                int startChar = ch;
                while(ASCII.isWord(ch) && ch != '>') ch=read();
                if(ch == '>'){
                    // valid group name
                    int len = cursor-start;
                    int[] newtemp = new int[2*(len) + 2];
                    //System.arraycopy(temp, start, newtemp, 0, len);
                    StringBuilder name = new StringBuilder();
                    for(int i = start; i< cursor; i++){
                        name.append((char)temp[i-1]);
                    }
                    // create Named group
                    head = createGroup(false);
                    ((GroupTail)root).name = name.toString();

                    capturingGroup = true;
                    tail = root;
                    head.next = expr(tail);
                    break;
                }
VonC
fonte
ambos os links acima parecem estar quebrados?
Jonas
Este código é de buggy. Ele está procurando identificadores ASCII. Isto é errado. Ele deve estar procurando por qualquer coisa que Java permita em um identificador !!
tchrist
1
Apenas para sua informação, uma vez que você parece tão consciente, a parte limitada não se refere tanto aos nomes ASCII x Unicode, mas apenas à possibilidade de ter um grupo nomeado por mesmo nome (sobre o qual você nem sempre tem controle!) E não podendo usá-los para recursão dentro da regex.
tchrist
@ tchrist: obrigado por essa precisão (incluída). Também adicionei um link para sua resposta estelar no "Java Regex helper" (votado).
VonC 12/08/11
Não existe um método matcher.name (int index) para o objeto Matcher em Java?
ot0 17/01/19
27

Sim, mas é bagunçado invadir as aulas de sol. Existe uma maneira mais simples:

http://code.google.com/p/named-regexp/

named-regexp é um invólucro fino para a implementação de expressões regulares do JDK padrão, com o único objetivo de manipular grupos de captura nomeados no estilo .net: (? ...).

Pode ser usado com Java 5 e 6 (genéricos são usados).

O Java 7 manipulará grupos de captura nomeados, portanto, este projeto não deve durar.

John Hardy
fonte
1
Pena que isso não pode ser usado no GWT.
Sakuraba
4
Confira o fork do GitHub deste projeto, que corrige vários bugs do original. Também está hospedado no Maven Central.
tony19
1
Apenas uma palavra de cautela no meu caso, o fork do tony19 no Github não funciona no Android a partir do 0.1.8.
mandril D
2
@RubberMallet, o problema específico do Android agora está corrigido e estará no 0.1.9.
precisa saber é o seguinte
2

Que tipo de problema você tem com o jregex ? Funcionou bem para mim no java5 e java6.

O Jregex faz bem o trabalho (mesmo que a última versão seja de 2002), a menos que você queira aguardar o javaSE 7 .

Brian Clozel
fonte
2

Para aqueles que executam pré-java7, os grupos nomeados são suportados pelo joni (porta Java da biblioteca regexp Oniguruma ). A documentação é escassa, mas funcionou bem para nós.
Os binários estão disponíveis via Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).

Ryan Smith
fonte
Estou muito interessado na opção joni mencionada por Ryan acima - você tem algum trecho de código usando grupos de captura nomeados? Consegui fazer com que a correspondência e a pesquisa básicas funcionem corretamente - mas não vejo qual método eu usaria para obtenha acesso aos groupNames ou obtenha o valor de uma captura usando o nome do grupo.
21712
1

Uma pergunta um pouco antiga, mas eu também estava precisando disso e que as sugestões acima eram inadequadas - e, como tal - desenvolvi um invólucro fino: https://github.com/hofmeister/MatchIt

Henrik Hofmeister
fonte