如何最好地检查一个字符串输入是否是一个有效的Java变量以进行编码?我相信我不是第一个想要这么做的人。但也许我错过了寻找有用信息的正确关键字。
最好的方法可能是使用正则表达式来检查以下内容:
以字母开头
然后可以包含数字、字母
可以包含一些特殊字符,比如 '_' (是哪些?)
- 不允许包含空格分隔符
public static boolean isValidJavaIdentifier(String s) {
if (s.isEmpty()) {
return false;
}
if (!Character.isJavaIdentifierStart(s.charAt(0))) {
return false;
}
for (int i = 1; i < s.length(); i++) {
if (!Character.isJavaIdentifierPart(s.charAt(i))) {
return false;
}
}
return true;
}
编辑:正如@Joey所指出的,您还应该过滤关键字和保留字。
)
。此外,字符串中的_
会使代码出错,因为它没有第二个字符。 - eis使用
import javax.lang.model.SourceVersion;
boolean isValidVariableName(CharSequence name) {
return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name);
}
如果您需要检查一个字符串是否为Java的合法变量名,在最新版本的Java中,或者
import javax.lang.model.SourceVersion;
boolean isValidVariableNameInVersion(CharSequence name, SourceVersion version) {
return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name, version);
}
如果您需要检查一个字符串在特定的Java版本中是否是有效的Java变量名称。
例如,从Java 9开始,下划线成为了保留关键字,因此isValidVariableNameInVersion("_", SourceVersion.RELEASE_9)
将返回false
,而isValidVariableNameInVersion("_", SourceVersion.RELEASE_8)
则将返回true
。
工作原理
SourceVersion.isIdentifier(CharSequence name)
检查name是否为最新源版本中的语法上有效的标识符(简单名称)或关键字。!SourceVersion.isKeyword(name)
对于关键字返回false。因此,SourceVersion.isIdentifier(name)&&!SourceVersion.isKeyword(name)
仅对有效的标识符返回true。
内置方法SourceVersion.isName(CharSequence name, SourceVersion version)
也使用相同的方法来检查name是否是语法上有效的限定名称,这意味着它将对类似于“apple.color”的字符串返回true
。
public static boolean isName(CharSequence name, SourceVersion version) {
String id = name.toString();
for(String s : id.split("\\.", -1)) {
if (!isIdentifier(s) || isKeyword(s, version))
return false;
}
return true;
}
测试
import org.junit.jupiter.api.Test;
import javax.lang.model.SourceVersion;
import static org.assertj.core.api.Assertions.assertThat;
public class ValidVariableNameTest {
boolean isValidVariableName(CharSequence name) {
return isValidVariableNameInVersion(name, SourceVersion.RELEASE_8);
}
boolean isValidVariableNameInVersion(CharSequence name, SourceVersion version) {
return SourceVersion.isIdentifier(name) && !SourceVersion.isKeyword(name, version);
}
@Test
void variableNamesCanBeginWithLetters() {
assertThat(isValidVariableName("test")).isTrue();
assertThat(isValidVariableName("e2")).isTrue();
assertThat(isValidVariableName("w")).isTrue();
assertThat(isValidVariableName("привет")).isTrue();
}
@Test
void variableNamesCanBeginWithDollarSign() {
assertThat(isValidVariableName("$test")).isTrue();
assertThat(isValidVariableName("$e2")).isTrue();
assertThat(isValidVariableName("$w")).isTrue();
assertThat(isValidVariableName("$привет")).isTrue();
assertThat(isValidVariableName("$")).isTrue();
assertThat(isValidVariableName("$55")).isTrue();
}
@Test
void variableNamesCanBeginWithUnderscore() {
assertThat(isValidVariableName("_test")).isTrue();
assertThat(isValidVariableName("_e2")).isTrue();
assertThat(isValidVariableName("_w")).isTrue();
assertThat(isValidVariableName("_привет")).isTrue();
assertThat(isValidVariableName("_55")).isTrue();
}
@Test
void variableNamesCannotContainCharactersThatAreNotLettersOrDigits() {
assertThat(isValidVariableName("apple.color")).isFalse();
assertThat(isValidVariableName("my var")).isFalse();
assertThat(isValidVariableName(" ")).isFalse();
assertThat(isValidVariableName("apple%color")).isFalse();
assertThat(isValidVariableName("apple,color")).isFalse();
assertThat(isValidVariableName(",applecolor")).isFalse();
}
@Test
void variableNamesCannotStartWithDigit() {
assertThat(isValidVariableName("2e")).isFalse();
assertThat(isValidVariableName("5")).isFalse();
assertThat(isValidVariableName("123test")).isFalse();
}
@Test
void differentSourceVersionsAreHandledCorrectly() {
assertThat(isValidVariableNameInVersion("_", SourceVersion.RELEASE_9)).isFalse();
assertThat(isValidVariableNameInVersion("_", SourceVersion.RELEASE_8)).isTrue();
assertThat(isValidVariableNameInVersion("enum", SourceVersion.RELEASE_9)).isFalse();
assertThat(isValidVariableNameInVersion("enum", SourceVersion.RELEASE_4)).isTrue();
}
@Test
void keywordsCannotBeUsedAsVariableNames() {
assertThat(isValidVariableName("strictfp")).isFalse();
assertThat(isValidVariableName("assert")).isFalse();
assertThat(isValidVariableName("enum")).isFalse();
// Modifiers
assertThat(isValidVariableName("public")).isFalse();
assertThat(isValidVariableName("protected")).isFalse();
assertThat(isValidVariableName("private")).isFalse();
assertThat(isValidVariableName("abstract")).isFalse();
assertThat(isValidVariableName("static")).isFalse();
assertThat(isValidVariableName("final")).isFalse();
assertThat(isValidVariableName("transient")).isFalse();
assertThat(isValidVariableName("volatile")).isFalse();
assertThat(isValidVariableName("synchronized")).isFalse();
assertThat(isValidVariableName("native")).isFalse();
// Declarations
assertThat(isValidVariableName("class")).isFalse();
assertThat(isValidVariableName("interface")).isFalse();
assertThat(isValidVariableName("extends")).isFalse();
assertThat(isValidVariableName("package")).isFalse();
assertThat(isValidVariableName("throws")).isFalse();
assertThat(isValidVariableName("implements")).isFalse();
// Primitive types and void
assertThat(isValidVariableName("boolean")).isFalse();
assertThat(isValidVariableName("byte")).isFalse();
assertThat(isValidVariableName("char")).isFalse();
assertThat(isValidVariableName("short")).isFalse();
assertThat(isValidVariableName("int")).isFalse();
assertThat(isValidVariableName("long")).isFalse();
assertThat(isValidVariableName("float")).isFalse();
assertThat(isValidVariableName("double")).isFalse();
assertThat(isValidVariableName("void")).isFalse();
// Control flow
assertThat(isValidVariableName("if")).isFalse();
assertThat(isValidVariableName("else")).isFalse();
assertThat(isValidVariableName("try")).isFalse();
assertThat(isValidVariableName("catch")).isFalse();
assertThat(isValidVariableName("finally")).isFalse();
assertThat(isValidVariableName("do")).isFalse();
assertThat(isValidVariableName("while")).isFalse();
assertThat(isValidVariableName("for")).isFalse();
assertThat(isValidVariableName("continue")).isFalse();
assertThat(isValidVariableName("switch")).isFalse();
assertThat(isValidVariableName("case")).isFalse();
assertThat(isValidVariableName("default")).isFalse();
assertThat(isValidVariableName("break")).isFalse();
assertThat(isValidVariableName("throw")).isFalse();
assertThat(isValidVariableName("return")).isFalse();
// Other keywords
assertThat(isValidVariableName("this")).isFalse();
assertThat(isValidVariableName("new")).isFalse();
assertThat(isValidVariableName("super")).isFalse();
assertThat(isValidVariableName("import")).isFalse();
assertThat(isValidVariableName("instanceof")).isFalse();
// Reserved keywords
assertThat(isValidVariableName("goto")).isFalse();
assertThat(isValidVariableName("const")).isFalse();
}
@Test
void literalsCannotBeUsedAsVariableNames() {
assertThat(isValidVariableName("null")).isFalse();
assertThat(isValidVariableName("true")).isFalse();
assertThat(isValidVariableName("false")).isFalse();
}
}
SourceVersion.isIdentifier()
单独不能用于检查字符串是否为有效的 Java 变量,因为它对关键字(如 null
、int
、true
、false
)返回 true
,这些关键字不能用作 Java 变量名。 - Denis Stafichuk
javax.lang.model.SourceVersion
类。它具有用于此类操作的方法。 - Amir Pashazadeh