Groupes nommés Regex en Java

173

Je crois comprendre que le java.regexpackage ne prend pas en charge les groupes nommés ( http://www.regular-expressions.info/named.html ), alors quelqu'un peut-il me diriger vers une bibliothèque tierce qui le fait?

J'ai regardé jregex mais sa dernière version date de 2002 et cela n'a pas fonctionné pour moi (certes, je n'ai essayé que brièvement) sous java5.

Dan
la source
3
Votre compréhension est incorrecte. JDK7 gère les groupes nommés.
tchrist
2
@tchrist En 2009, il n'y avait pas de JDK7.
Alex78191

Réponses:

276

( Mise à jour : août 2011 )

Comme le mentionne geofflane dans sa réponse , Java 7 prend désormais en charge les groupes nommés .
tchrist souligne dans le commentaire que le support est limité.
Il détaille les limites dans sa grande réponse " Java Regex Helper "

Java 7 regex named group support a été présenté en septembre 2010 sur le blog d'Oracle .

Dans la version officielle de Java 7, les constructions pour prendre en charge le groupe de capture nommé sont:

  • (?<name>capturing text) pour définir un groupe nommé "nom"
  • \k<name> pour référencer un groupe nommé "nom"
  • ${name} pour faire référence au groupe capturé dans la chaîne de remplacement de Matcher
  • Matcher.group(String name) pour renvoyer la sous-séquence d'entrée capturée par le "groupe nommé" donné.

D'autres alternatives pour pré-Java 7 étaient:


( Réponse originale : janvier 2009 , avec les deux liens suivants maintenant rompus)

Vous ne pouvez pas faire référence à un groupe nommé, sauf si vous codez votre propre version de Regex ...

C'est précisément ce que Gorbush2 a fait dans ce fil .

Regex2

(implémentation limitée, comme souligné à nouveau par tchrist , car il ne recherche que les identifiants ASCII. tchrist détaille la limitation comme:

ne pouvoir avoir qu'un seul groupe nommé par même nom (sur lequel vous n'avez pas toujours le contrôle!) et ne pas pouvoir les utiliser pour la récursivité in-regex.

Remarque: vous pouvez trouver de vrais exemples de récursions de regex dans les expressions régulières Perl et PCRE, comme mentionné dans la diapositive Regexp Power , PCRE specs and Matching Strings with Balanced Parentheses )

Exemple:

Chaîne:

"TEST 123"

RegExp:

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

Accès

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

Remplacer

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

(extrait de l'implémentation)

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
la source
les deux liens ci-dessus semblent être rompus?
Jonas
Ce code est bogué. Il recherche des identifiants ASCII. C'est faux. Il devrait chercher tout ce que Java autorise dans un identifiant !!
tchrist
1
Juste pour info puisque vous semblez si consciencieux, la partie limitée ne concerne pas tant les noms ASCII vs Unicode que le fait de ne pouvoir avoir qu'un groupe nommé par même nom (sur lequel vous n'avez pas toujours le contrôle!) Et ne pas pouvoir les utiliser pour la récursivité in-regex.
tchrist
@tchrist: merci pour cette précision (incluse). J'ai également ajouté un lien vers votre réponse stellaire sur "Java Regex helper" (upvoté).
VonC
Il n'y a pas de méthode matcher.name (index int) pour l'objet Matcher en Java ??
ot0
27

Oui, mais son piratage désordonné des classes de soleil. Il existe un moyen plus simple:

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

named-regexp est un wrapper léger pour l'implémentation d'expressions régulières JDK standard, dans le seul but de gérer les groupes de capture nommés dans le style .net: (? ...).

Il peut être utilisé avec Java 5 et 6 (des génériques sont utilisés).

Java 7 gérera les groupes de capture nommés, ce projet n'est donc pas destiné à durer.

John Hardy
la source
1
Dommage que cela ne puisse pas être utilisé depuis GWT.
Sakuraba
4
Découvrez le fork GitHub de ce projet, qui corrige plusieurs bogues de l'original. Il est également hébergé à Maven Central.
tony19
1
Juste un mot d'avertissement dans mon cas, la fourche tony19 sur Github ne fonctionne pas sur Android à partir de la 0.1.8.
Chuck D
2
@RubberMallet, Le problème spécifique à Android est maintenant résolu et sera dans la version 0.1.9.
tony19
2

Quel genre de problème rencontrez-vous avec jregex ? Cela a bien fonctionné pour moi sous java5 et java6.

Jregex fait bien le travail (même si la dernière version date de 2002), sauf si vous voulez attendre javaSE 7 .

Brian Clozel
la source
2

Pour ceux exécutant pré-java7, les groupes nommés sont pris en charge par joni (port Java de la bibliothèque de regexp d' Oniguruma ). La documentation est rare, mais elle a bien fonctionné pour nous.
Les binaires sont disponibles via Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).

Ryan Smith
la source
Je suis très intéressé par l'option joni mentionnée par Ryan ci-dessus - avez-vous des extraits de code utilisant des groupes de capture nommés - j'ai réussi à obtenir une correspondance de base et une recherche pour fonctionner correctement - mais je ne vois pas quelle méthode j'utiliserais pour accéder aux groupNames ou pour obtenir la valeur d'une capture en utilisant le nom du groupe.
malsmith
1

Une question un peu ancienne mais je me suis retrouvé besoin de cela aussi et que les suggestions ci-dessus étaient inadéquates - et en tant que telles - j'ai moi-même développé un mince emballage: https://github.com/hofmeister/MatchIt

Henrik Hofmeister
la source