正则表达式匹配完全限定的类名

时间:2011-03-05 17:09:47

标签: java regex class matching fully-qualified-naming

在文本中匹配完全限定的Java类名称的最佳方法是什么?

示例:java.lang.Reflectjava.util.ArrayListorg.hibernate.Hibernate

9 个答案:

答案 0 :(得分:67)

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

它们也不能是保留字(例如importtruenull)。如果您只想检查合理性,以上就足够了。如果您还想检查有效期,则还必须检查保留字列表。

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 Language Specification, (section 3.8)包含有效标识符名称的所有详细信息。

另请参阅此问题的答案:Java Unicode variable names

答案 1 :(得分:7)

这是一个完全按照@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"));
    }
}

答案 2 :(得分:5)

Renaud提供的模式有效。但是,据我所知,它最终总是会回溯。

为了优化它,您基本上可以将前半部分与最后一部分交换。请注意您还需要更改的点匹配。

以下是我的版本,与原版相比,运行速度快了两倍:

UserController

我不能写评论,所以我决定写一个答案。

答案 3 :(得分:3)

我(我自己)得到了一个类似的答案(如Tomalak的答案),就像M.M.M.N:

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

其中,

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

然而,这个正则表达式(与Tomalak的答案不同)做出了更多的假设:

  1. 包裹名称(M部分)仅为小写,M的第一个字符始终为低位字母,其余字符可以混合下划线,下划线和数字。

  2. 班级名称(N部分)将始终以大写字母或下划线开头,其余可以混合下划线,字母和数字。内部类始终以美元符号($)开头,并且必须遵守前面描述的类名规则。

  3. 注意:模式\ w是字母和数字的XSD模式(它不包括下划线符号(_))

    希望得到这个帮助。

答案 4 :(得分:0)

以下表达对我来说非常好。

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

答案 5 :(得分:0)

以下类验证提供的包名称是否有效:

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

答案 6 :(得分:0)

工作正则表达式的缩短版本:

\p{Alnum}[\p{Alnum}._]+\p{Alnum}

答案 7 :(得分:0)

对于像com.mycompany.core.functions.CustomFunction这样的字符串,我正在使用((?:(?:\w+)?\.[a-z_A-Z]\w+)+)

答案 8 :(得分:-3)

我会说([\w]+\.)*[\w]+

之类的东西

但也许我可以更具体地了解你想用它做什么;)

相关问题