web-dev-qa-db-fra.com

Groupes nommés Regex dans Java

Je crois comprendre que le Java.regex Le package ne prend pas en charge les groupes nommés ( http://www.regular-expressions.info/named.html ). Quelqu'un peut-il m'indiquer une bibliothèque tierce qui en possède?

J'ai jeté un œil à 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.

156
Dan

( Mise à jour : août 2011 )

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

L'assistance de groupe nommé Java 7 regex a été présentée dans 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 les suivantes:

  • (?<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é.

Les autres alternatives pour les versions antérieures à Java 7 étaient les suivantes:


( Réponse originale : janvier 2009 , les deux liens suivants étant 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 elle ne recherche que les identifiants ASCII. tchrist détaille la limitation comme suit:

seulement pouvoir avoir 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écursion dans les regex.

Remarque: Vous pouvez trouver de vrais exemples de récursivité des expressions rationnelles dans les expressions rationnelles Perl et PCRE, comme indiqué dans Expression rationnelle , spécifications PCRE et Correspondance des chaînes avec des parenthèses équilibrées faire glisser)

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;
                }
255
VonC

Oui, mais c'est compliqué de pirater les classes du soleil. Il y a un moyen plus simple:

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

named-regexp est un wrapper fin pour l'implémentation des 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, de sorte que ce projet n'est pas conçu pour durer.

27
John Hardy

Pour les personnes qui arrivent trop tard: Java 7 ajoute des groupes nommés. Documentation sur Matcher.group (String groupName).

25
geofflane

Pour ceux qui exécutent une version antérieure à Java7, les groupes nommés sont pris en charge par joni (port Java de la bibliothèque Oniguruma regexp). La documentation est rare, mais cela a bien fonctionné pour nous.
Les fichiers binaires sont disponibles via Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).

2
Ryan Smith

Quel genre de problème avez-vous avec jregex ? Cela fonctionnait bien pour moi sous Java5 et Java6.

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

2
Brian Clozel

Une question un peu ancienne, mais je me suis retrouvée à en avoir besoin également et que les suggestions ci-dessus étaient inadéquates - et en tant que telles - ont été développées moi-même: https://github.com/hofmeister/MatchIt

1