如何在文本中匹配完整的Java类名?
例如:java.lang.Reflect
,java.util.ArrayList
,org.hibernate.Hibernate
。
如何在文本中匹配完整的Java类名?
例如:java.lang.Reflect
,java.util.ArrayList
,org.hibernate.Hibernate
。
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变量名
\p{Currency_Symbol}
或\p{Sc}
代替$
。想一想,一个调用isJavaIdentifierPart()
和isJavaIdentifierStart()
的小解析器会使代码更简洁。 - Tomalak"(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*\\.)+\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"
。优雅,这就是Java! - Alan Moore\p{Currency_Symbol}
,但它可以识别\p{Sc}
。我还没有进行更多测试,但我必须这样做,因为RegexBuddy对我的工作流程非常重要。 - aliteralmind([\p{L}_\p{Sc}][\p{L}\p{N}_\p{Sc}]*\.)+
。 - aliteralmind这里是一个完全可行的类和测试,基于@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"));
}
}
VALID_JAVA_IDENTIFIER
这个名称不太合适,因为这个模式代表一个完全限定类名。我建议提取 String ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"
以使其更加明显和易读。 - TWiStErRobVALID_JAVA_IDENTIFIER
代表FQCN时,不确定您的意思是什么?此外,不确定ID_PATTERN
更易读...感谢您的解释。 - RenaudRenaud提供的模式是有效的,但他原始的答案在结尾处总是会回溯。
为了优化它,您可以将前半部分与后半部分互换。请注意,您还需要更改点匹配。
以下是我修改后的版本,与原始版本相比,运行速度约快两倍:
String ID_PATTERN = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
Pattern FQCN = Pattern.compile(ID_PATTERN + "(\\." + ID_PATTERN + ")*");
我无法编写注释,因此我决定编写回答。
我自己也得出了类似的答案(和Tomalak的答案相似),即M.M.M.N:
([a-z][a-z_0-9]*\.)*[A-Z_]($[A-Z_]|[\w_])*
Where,
M = ([a-z][a-z_0-9]*\.)*
N = [A-Z_]($[A-Z_]|[\w_])*
然而,与Tomalak的答案不同,该正则表达式做出了更多的假设:
包名(M部分)只能使用小写字母,M的第一个字符始终为小写字母,其余部分可以混合使用下划线、小写字母和数字。
类名(N部分)始终以大写字母或下划线开头,其余部分可以混合使用下划线、字母和数字。内部类始终以美元符号($)开头,并必须遵守先前描述的类名规则。
注意:模式\w是字母和数字的XSD模式(不包括下划线符号(_)
希望这有所帮助。
一个工作正则表达式的简短版本:
\p{Alnum}[\p{Alnum}._]+\p{Alnum}
对于类似 com.mycompany.core.functions.CustomFunction 的字符串,我使用 ((?:(?:\w+)?\.[a-z_A-Z]\w+)+)
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;
}
}
以下表达式对我来说完全正常运行。
^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$
我会说类似于([\w]+\.)*[\w]+
这样的话。
但是,如果你告诉我你想用它做什么,我可能可以更具体一些;)
[]
,这个正则表达式 (\\w+\\.?)+
就足够了。 - Johan Sjöberg
import
语句?如果只需移除;
,则不要使用正则表达式。 - Johan Sjöbergjavax.lang.model.SourceVersion.isName(CharSequence)
。 - Hollis Waite