11

是否有一些很好的方法来检查某个字符串是否代表一个有效的(完全限定的)Java 类名?例如org.comPAny.ClassName,甚至mYcRAZYcLASSnAME是有效的类名,但类似org..package.MyClassorg.ClassName.不是。我想在不加载该类的情况下检查类名的有效性。

Java中有一些方便的方法来检查吗?或者你能提供被授予涵盖所有情况的正则表达式吗?

编辑:请不要建议第三方库。

4

7 回答 7

10

如果您真的想要一个防弹解决方案,"\\."请先将字符串拆分并使用

Character.isJavaIdentifierStart

和循环中

Character.isJavaIdentifierPart

检查零件是否是有效的标识符名称。

 

编辑: #split(String)将字符串解释为正则表达式,因此请确保将字符串拆分,"\\."而不是"."按照最少意外原则所期望的那样。多么糟糕的 API 设计,哎呀!这就是你在你的语言中没有正则表达式文字所得到的……</p>

于 2012-11-26T00:45:05.350 回答
7

正确的方法是使用javax.lang.model.SourceVersion.isName方法(Java 标准库的一部分)。

于 2017-09-12T21:26:35.123 回答
3
public static boolean isValidJavaIdentifier(String s)
{
 // an empty or null string cannot be a valid identifier
 if (s == null || s.length() == 0)
 {
    return false;
 }

 char[] c = s.toCharArray();
 if (!Character.isJavaIdentifierStart(c[0]))
 {
    return false;
 }

 for (int i = 1; i < c.length; i++)
 {
    if (!Character.isJavaIdentifierPart(c[i]))
    {
       return false;
    }
 }

 return true;
}

参考: http ://www.java2s.com/Code/Java/Reflection/CheckwhetherthegivenStringisavalididentifieraccordingtotheJavaLanguagespecifications.htm

于 2012-11-26T00:48:51.587 回答
3

不同版本的 Java 平台支持不同的 Unicode 版本。

所以不同的版本会支持不同的有效标识符。

以下说明了 BMP 之外的标识符和 Java 保留字。

import java.util.Arrays;

public enum PackageName {

  SIMPLE, QUALIFIED, INVALID;

    public static final PackageName check(String name) {
    PackageName ret = PackageName.INVALID;
    int[] codePoint;
    int index = 0, dotex = -1;
    boolean needStart = true;
    escape: {
      if(name == null || name.isEmpty()) break escape;
      if(name.codePointAt(0) == '.') break escape;
      codePoint = name.codePoints().toArray();
      while (index <= codePoint.length) {
        if(index == codePoint.length) {
          if(codePoint[index - 1] == '.'){
            ret = PackageName.INVALID; break escape;}
          int start = dotex + 1;
          int end = index;
          start = name.offsetByCodePoints(0, start);
          end = name.offsetByCodePoints(0, end);
          String test = name.substring(start, end);
          if(!(Arrays.binarySearch(reserved, test) < 0)){
            ret = PackageName.INVALID; break escape;}
          if(!(ret == PackageName.QUALIFIED)) ret = PackageName.SIMPLE;
          break escape;
        }
        if(codePoint[index] == '.') {
          if(codePoint[index - 1] == '.'){
            ret = PackageName.INVALID;  break escape;}
          else {
            needStart = true;
            int start = dotex + 1;
            int end = index;
            start = name.offsetByCodePoints(0, start);
            end = name.offsetByCodePoints(0, end);
            String test = name.substring(start, end);
            if(!(Arrays.binarySearch(reserved, test) < 0)) break escape;
            dotex = index;
            ret = PackageName.QUALIFIED;
          }
        } else if(Character.isJavaIdentifierStart(codePoint[index])) {
          if(needStart) needStart = false;
        } else if((!Character.isJavaIdentifierPart(codePoint[index]))){
          ret = PackageName.INVALID; break escape;
        } 
        index++;
      }
    }
    return ret;
  }

  private static final String[] reserved;

  static {
    reserved = new String[] { "abstract", "assert", "boolean", "break", "byte",
        "case", "catch", "char", "class", "const", "continue", "default", "do",
        "double", "else", "enum", "extends", "false", "final", "finally",
        "float", "for", "if", "goto", "implements", "import", "instanceof",
        "int", "interface", "long", "native", "new", "null", "package",
        "private", "protected", "public", "return", "short", "static",
        "strictfp", "super", "switch", "synchronized", "this", "throw",
        "throws", "transient", "true", "try", "void", "volatile", "while" };
  }
}
于 2014-11-13T22:01:35.567 回答
2

您的问题有一个很好的解决方案:

public static boolean isFullyQualifiedClassname( String classname ) {
      if (classname == null) return false;
      String[] parts = classname.split("[\\.]");
      if (parts.length == 0) return false;
      for (String part : parts) {
          CharacterIterator iter = new StringCharacterIterator(part);
          // Check first character (there should at least be one character for each part) ...
          char c = iter.first();
          if (c == CharacterIterator.DONE) return false;
          if (!Character.isJavaIdentifierStart(c) && !Character.isIdentifierIgnorable(c)) return false;
          c = iter.next();
          // Check the remaining characters, if there are any ...
          while (c != CharacterIterator.DONE) {
              if (!Character.isJavaIdentifierPart(c) && !Character.isIdentifierIgnorable(c)) return false;
              c = iter.next();
          }
      }
      return true;
  }

资料来源:http ://www.java2s.com/Code/Java/Reflection/DeterminewhetherthesuppliedstringrepresentsawellformedfullyqualifiedJavaclassname.htm

于 2014-04-11T12:02:48.920 回答
1

你见过这个吗 ?

http://commons.apache.org/sandbox/classscan/apidocs/org/apache/commons/classscan/builtin/ClassNameHelper.html

这里方法isValidIdentifier*检查提供的名称是否是有效的 java 包名称部分或类标识符。

于 2012-11-26T06:49:19.237 回答
0

使用正则表达式可以轻松实现防弹解决方案:

String NAME = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*";
String DOT = "\\.";
String DOTTED_NAME = NAME + "(?:" + DOT + NAME + ")*";
Pattern DOTTED_NAME_PATTERN = Pattern.compile(DOTTED_NAME);

boolean isJavaName(String name) {
    Matcher matcher = DOTTED_NAME_PATTERN.matcher(name);
    return matcher.matches();
}
于 2019-06-12T17:03:43.323 回答