web-dev-qa-db-fra.com

Expression régulière correspondant à des noms de classe pleinement qualifiés

Quelle est la meilleure façon de faire correspondre le nom de classe Java qualifié complet dans un texte? 

Exemples: Java.lang.Reflect, Java.util.ArrayList, org.hibernate.Hibernate.

34
Chun ping Wang

Un nom de classe complet Java (disons "N") a la structure

N.N.N.N

La partie "N" doit être un identifiant Java. Les identificateurs Java ne peuvent pas commencer par un nombre, mais après le caractère initial, ils peuvent utiliser n'importe quelle combinaison de lettres et de chiffres, de tirets de soulignement ou de signes dollar:

([a-zA-Z_$][a-zA-Z\d_$]*\.)*[a-zA-Z_$][a-zA-Z\d_$]*
------------------------    -----------------------
          N                           N

Ils ne peuvent pas non plus être un mot réservé (comme import, true ou null). Si vous voulez vérifier plausibility uniquement, ce qui précède suffit. Si vous souhaitez également vérifier validité, vous devez également vérifier une liste de mots réservés.

Les identifiants Java peuvent contenir n'importe quelle lettre Unicode au lieu de "latin uniquement". Si vous souhaitez également vérifier cela, utilisez les classes de caractères Unicode:

([\p{Letter}_$][\p{Letter}\p{Number}_$]*\.)*[\p{Letter}_$][\p{Letter}\p{Number}_$]*

ou, pour faire court

([\p{L}_$][\p{L}\p{N}_$]*\.)*[\p{L}_$][\p{L}\p{N}_$]*

La Spécification du langage Java, (section 3.8) contient tous les détails sur les noms d'identificateurs valides.

Voir également la réponse à cette question: Noms de variables Java Unicode

66
Tomalak

Voici une classe entièrement ouvrière avec des tests, basée sur l'excellent commentaire de @ alan-moore

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import Java.util.regex.Pattern;

import org.junit.Test;

public class ValidateJavaIdentifier {

    private static final String ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
    private static final Pattern FQCN = Pattern.compile(ID_PATTERN + "(\\." + ID_PATTERN + ")*");

    public static boolean validateJavaIdentifier(String identifier) {
        return FQCN.matcher(identifier).matches();
    }


    @Test
    public void testJavaIdentifier() throws Exception {
        assertTrue(validateJavaIdentifier("C"));
        assertTrue(validateJavaIdentifier("Cc"));
        assertTrue(validateJavaIdentifier("b.C"));
        assertTrue(validateJavaIdentifier("b.Cc"));
        assertTrue(validateJavaIdentifier("aAa.b.Cc"));
        assertTrue(validateJavaIdentifier("a.b.Cc"));

        // after the initial character identifiers may use any combination of
        // letters and digits, underscores or dollar signs
        assertTrue(validateJavaIdentifier("a.b.C_c"));
        assertTrue(validateJavaIdentifier("a.b.C$c"));
        assertTrue(validateJavaIdentifier("a.b.C9"));

        assertFalse("cannot start with a dot", validateJavaIdentifier(".C"));
        assertFalse("cannot have two dots following each other",
                validateJavaIdentifier("b..C"));
        assertFalse("cannot start with a number ",
                validateJavaIdentifier("b.9C"));
    }
}
7
Renaud

Le modèle fourni par Renaud fonctionne. Mais, autant que je sache, il y aura toujours un retour en arrière à la fin.

Pour l'optimiser, vous pouvez essentiellement échanger la première moitié avec la dernière. Notez la correspondance de points que vous devez également modifier.

Ce qui suit est ma version de celui-ci qui, comparé à l'original, est environ deux fois plus rapide:

String ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
Pattern FQCN = Pattern.compile(ID_PATTERN + "(\\." + ID_PATTERN + ")*");

Je ne peux pas écrire de commentaires, j'ai donc décidé d'écrire une réponse à la place.

4
Jörgen Lundgren

Je suis venu (seul) à une réponse similaire (comme la réponse de Tomalak), quelque chose comme M.M.N.

([a-z][a-z_0-9]*\.)*[A-Z_]($[A-Z_]|[\w_])*

Où,

M = ([a-z][a-z_0-9]*\.)*
N = [A-Z_]($[A-Z_]|[\w_])*

Cependant, cette expression régulière (contrairement à la réponse de Tomalak) repose sur d'autres hypothèses:

  1. Le nom du paquet (la partie M) sera uniquement en minuscule, le premier caractère de M sera toujours une lettre inférieure, le reste pouvant mélanger le trait de soulignement, les lettres minuscules et les chiffres.

  2. Le nom de classe (la partie N) commence toujours par une lettre majuscule ou un trait de soulignement, le reste peut mélanger un trait de soulignement, des lettres et des chiffres. Les classes intérieures commencent toujours par un symbole dollar ($) et doivent obéir aux règles de nom de classe décrites précédemment.

Remarque: le modèle\w est le modèle XSD pour les lettres et les chiffres (il ne comprend pas le symbole de soulignement (_))

J'espère que cette aide.

3
Carlitos Way

L'expression suivante fonctionne parfaitement pour moi.

^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$
0
gopalanrc

version plus courte d'une expression rationnelle de travail:

\p{Alnum}[\p{Alnum}._]+\p{Alnum}
0
Diego Plentz

La classe suivante valide qu'un nom de package fourni est valide:

import Java.util.HashSet;

public class ValidationUtils {

    // All Java reserved words that must not be used in a valid package name.
    private static final HashSet reserved;

    static {
        reserved = new HashSet();
        reserved.add("abstract");reserved.add("assert");reserved.add("boolean");
        reserved.add("break");reserved.add("byte");reserved.add("case");
        reserved.add("catch");reserved.add("char");reserved.add("class");
        reserved.add("const");reserved.add("continue");reserved.add("default");
        reserved.add("do");reserved.add("double");reserved.add("else");
        reserved.add("enum");reserved.add("extends");reserved.add("false");
        reserved.add("final");reserved.add("finally");reserved.add("float");
        reserved.add("for");reserved.add("if");reserved.add("goto");
        reserved.add("implements");reserved.add("import");reserved.add("instanceof");
        reserved.add("int");reserved.add("interface");reserved.add("long");
        reserved.add("native");reserved.add("new");reserved.add("null");
        reserved.add("package");reserved.add("private");reserved.add("protected");
        reserved.add("public");reserved.add("return");reserved.add("short");
        reserved.add("static");reserved.add("strictfp");reserved.add("super");
        reserved.add("switch");reserved.add("synchronized");reserved.add("this");
        reserved.add("throw");reserved.add("throws");reserved.add("transient");
        reserved.add("true");reserved.add("try");reserved.add("void");
        reserved.add("volatile");reserved.add("while");
    }

    /**
     * Checks if the string that is provided is a valid Java package name (contains only
     * [a-z,A-Z,_,$], every element is separated by a single '.' , an element can't be one of Java's
     * reserved words.
     *
     * @param name The package name that needs to be validated.
     * @return <b>true</b> if the package name is valid, <b>false</b> if its not valid.
     */
    public static final boolean isValidPackageName(String name) {
        String[] parts=name.split("\\.",-1);
        for (String part:parts){
            System.out.println(part);
            if (reserved.contains(part)) return false;
            if (!validPart(part)) return false;
        }
        return true;
    }

    /**
     * Checks that a part (a Word between dots) is a valid part to be used in a Java package name.
     * @param part The part between dots (e.g. *PART*.*PART*.*PART*.*PART*).
     * @return <b>true</b> if the part is valid, <b>false</b> if its not valid.
     */
    private static boolean validPart(String part){
        if (part==null || part.length()<1){
            // Package part is null or empty !
            return false;
        }
        if (Character.isJavaIdentifierStart(part.charAt(0))){
            for (int i = 0; i < part.length(); i++){
                char c = part.charAt(i);
                if (!Character.isJavaIdentifierPart(c)){
                    // Package part contains invalid JavaIdentifier !
                    return false;
                }
            }
        }else{
            // Package part does not begin with a valid JavaIdentifier !
            return false;
        }

        return true;
    }
}
0
David Lev