java - solo - Expresión regular que coincide con nombres de clase completamente calificados
extraer cadenas con expresiones regulares java (8)
Aquí hay una clase totalmente trabajadora con pruebas, basada en el excelente comentario 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"));
}
}
¿Cuál es la mejor manera de hacer coincidir el nombre de la clase Java totalmente calificado en un texto?
Ejemplos: java.lang.Reflect
, java.util.ArrayList
, org.hibernate.Hibernate
.
Diré algo como ([/w]+/.)*[/w]+
Pero tal vez pueda ser más específico sabiendo lo que quieres hacer con él;)
El patrón provisto por Renaud funciona. Pero, por lo que puedo decir, siempre retrocederá al final.
Para optimizarlo, esencialmente puedes intercambiar la primera mitad con la última. Tenga en cuenta la coincidencia de puntos que también necesita cambiar.
La siguiente es mi versión de que, en comparación con el original, se ejecuta aproximadamente el doble de rápido:
String ID_PATTERN = "//p{javaJavaIdentifierStart}//p{javaJavaIdentifierPart}*";
Pattern FQCN = Pattern.compile(ID_PATTERN + "(//." + ID_PATTERN + ")*");
No puedo escribir comentarios, así que decidí escribir una respuesta.
La siguiente clase valida que un nombre de paquete proporcionado sea válido:
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;
}
}
La siguiente expresión funciona perfectamente bien para mí.
^[a-z][a-z0-9_]*(/.[a-z0-9_]+)+$
Un nombre de clase completo de Java (digamos "N") tiene la estructura
N.N.N.N
La parte "N" debe ser un identificador de Java. Los identificadores Java no pueden comenzar con un número, pero después del carácter inicial pueden usar cualquier combinación de letras y dígitos, guiones bajos o signos de dólar:
([a-zA-Z_$][a-zA-Z/d_$]*/.)*[a-zA-Z_$][a-zA-Z/d_$]*
------------------------ -----------------------
N N
Tampoco pueden ser palabras reservadas (como import
, true
o null
). Si desea verificar la plausibilidad solamente, lo anterior es suficiente. Si también desea verificar la validez , también debe consultar con una lista de palabras reservadas.
Los identificadores de Java pueden contener cualquier letra Unicode en lugar de "solo en latín". Si desea comprobar esto también, use clases de caracteres Unicode:
([/p{Letter}_$][/p{Letter}/p{Number}_$]*/.)*[/p{Letter}_$][/p{Letter}/p{Number}_$]*
o, para abreviar
([/p{L}_$][/p{L}/p{N}_$]*/.)*[/p{L}_$][/p{L}/p{N}_$]*
La Especificación del lenguaje Java (sección 3.8) contiene todos los detalles sobre los nombres de identificadores válidos.
Consulte también la respuesta a esta pregunta: nombres de variables Java Unicode
Vine (por mi cuenta) a una respuesta similar (como la respuesta de Tomalak), algo así como MMMN:
([a-z][a-z_0-9]*/.)*[A-Z_]($[A-Z_]|[/w_])*
Dónde,
M = ([a-z][a-z_0-9]*/.)*
N = [A-Z_]($[A-Z_]|[/w_])*
Sin embargo, esta expresión regular (a diferencia de la respuesta de Tomalak) hace más suposiciones:
El nombre del paquete (la parte M) estará solo en minúscula, el primer carácter de M siempre será una letra más baja, el resto puede mezclar guiones bajos, letras más bajas y números.
El nombre de la clase (la parte N) siempre comenzará con una letra mayúscula o un guión bajo, el resto puede mezclar guiones bajos, letras y números. Las clases internas siempre comienzan con un símbolo de dólar ($) y deben obedecer las reglas de nombre de clase descritas anteriormente.
Nota: el patrón / w es el patrón XSD para letras y dígitos (no incluye el símbolo de subrayado (_))
Espero que esto ayude.
versión más corta de una expresión regular funcional:
/p{Alnum}[/p{Alnum}._]+/p{Alnum}