Регулярное выражение, совпадающее с полностью определенными именами классов - PullRequest
35 голосов
/ 05 марта 2011

Каков наилучший способ сопоставить полное имя класса Java в тексте?

Примеры: java.lang.Reflect, java.util.ArrayList, org.hibernate.Hibernate.

Ответы [ 8 ]

67 голосов
/ 05 марта 2011

Полное имя класса Java (скажем, «N») имеет структуру

N.N.N.N

Часть «N» должна быть идентификатором Java.Идентификаторы Java не могут начинаться с цифры, но после начального символа они могут использовать любую комбинацию букв и цифр, символов подчеркивания или знака доллара:

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

Они также не могут быть зарезервированным словом (например, import, true или null).Если вы хотите проверить только правдоподобие , этого достаточно.Если вы также хотите проверить достоверность , вы должны также проверить список зарезервированных слов.

Идентификаторы Java могут содержать любую букву Unicode вместо «только латинский».Если вы также хотите проверить это, используйте классы символов Unicode:

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

или, для краткости

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

Спецификация языка Java, (раздел 3.8) содержит все сведения о допустимых именах идентификаторов.

Также см. Ответ на этот вопрос: Имена переменных Java Unicode

7 голосов
/ 19 декабря 2014

Это полностью рабочий класс с тестами, основанный на превосходном комментарии от @ 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"));
    }
}
5 голосов
/ 05 июня 2015

Шаблон, представленный работами Рено.Но, насколько я могу судить, в конце он всегда будет возвращаться назад.

Чтобы оптимизировать его, вы можете по существу поменять первую половину на последнюю.Обратите внимание на совпадение точек, которое вам также необходимо изменить.

Ниже приведена моя версия, которая по сравнению с оригиналом работает примерно вдвое быстрее:

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

Я не могу написатькомментарии, поэтому я решил написать ответ.

3 голосов
/ 07 сентября 2013

Я пришел (самостоятельно) к аналогичному ответу (как ответ Томалака), что-то вроде М.М.М.М.Н:

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

Где,

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

Однако, это регулярное выражение (в отличие от ответа Томалака) делает больше предположений:

  1. Имя пакета (часть M) будет только в нижнем регистре, первый символ M всегда будет строчной буквой, остальные могут смешивать подчеркивание, строчные буквы и цифры.

  2. Имя класса (часть N) всегда начинается с заглавной буквы или подчеркивания, остальные могут смешивать подчеркивание, буквы и цифры. Внутренние классы всегда начинаются с символа доллара ($) и должны подчиняться правилам имени класса, описанным ранее.

Примечание: шаблон \ w является шаблоном XSD для букв и цифр (не включает символ подчеркивания (_))

Надеюсь, эта помощь.

0 голосов
/ 22 марта 2017

более короткая версия рабочего регулярного выражения:

\p{Alnum}[\p{Alnum}._]+\p{Alnum}
0 голосов
/ 02 января 2017

Следующий класс проверяет правильность указанного имени пакета:

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 голосов
/ 28 июля 2016

Следующее выражение прекрасно работает для меня.

^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$
0 голосов
/ 05 марта 2011

Я скажу что-то вроде ([\w]+\.)*[\w]+

Но, возможно, я могу быть более конкретным, зная, что вы хотите с ним делать;)

...