web-dev-qa-db-ja.com

完全修飾クラス名に一致する正規表現

テキスト内の完全修飾Javaクラス名を照合する最良の方法は何ですか?

例:Java.lang.ReflectJava.util.ArrayListorg.hibernate.Hibernate

38
Chun ping Wang

A 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など)。 妥当性のみを確認したい場合は、上記で十分です。 validityもチェックする場合は、予約語のリストもチェックする必要があります。

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変数名

71
Tomalak

@ 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

ルノーが提供するパターンは機能します。しかし、私が知る限り、それは常に最後に戻ります。

それを最適化するには、基本的に前半を後半と交換できます。変更する必要があるドットの一致に注意してください。

以下は私のバージョンで、オリジナルと比較すると約2倍の速度で実行されます。

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

コメントは書けないので、代わりに回答を書くことにしました。

5

私は(自分で)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_])*

ただし、この正規表現(トマラックの回答とは異なります)は、より多くの仮定を行います。

  1. パッケージ名(M部分)は小文字のみで、Mの最初の文字は常に小文字で、残りはアンダースコア、小文字、数字を混在させることができます。

  2. クラス名(N部分)は常に大文字またはアンダースコアで始まり、残りはアンダースコア、文字、数字を混在させることができます。内部クラスは常にドル記号($)で始まり、前述のクラス名の規則に従う必要があります。

注:パターン\ wは、文字と数字のXSDパターンです(アンダースコア記号(_)は含まれません)。

この助けを願っています。

3
Carlitos Way

次の表現は、私にとってはまったく問題ありません。

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

Com.mycompany.core.functions.CustomFunctionのような文字列の場合、((?:(?:\w+)?\.[a-z_A-Z]\w+)+)

0
Georgi Stoyanov

動作する正規表現の短いバージョン:

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

次のクラスは、提供されたパッケージ名が有効であることを検証します。

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