Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Kiểm tra chuỗi có phải từ khóa (keyword) hợp lệ trong Java

Bài toán: Kiểm tra một chuỗi có tuân theo quy tắc đặt tên identifier (biến, phương thức, lớp) trong Java hay không. Lưu ý: "Valid keyword" trong tiêu đề gốc hơi nhầm lẫn – keyword là từ khóa dành riêng (if, for, class...), không thể dùng làm identifier. Code thực tế kiểm tra valid identifier.

Quy tắc Java Identifier

  • Ký tự đầu: Chữ cái (a-z, A-Z), underscore (_), dollar sign ($). Không được bắt đầu bằng số.
  • Ký tự tiếp theo: Chữ cái, số (0-9), underscore, dollar sign.
  • Không được là reserved keywords (50+ từ: if, else, class, int, static...).
  • Không được là true, false, null (literals).
  • Độ dài: không giới hạn (thực tế hạn chế bởi JVM/class file format ~64KB).
  • Unicode: Hỗ trợ chữ cái Unicode (Letter category), không chỉ ASCII.

Cách 1: Regex (Đơn giản, ASCII only)

public class IdentifierValidator {
    // Regex ASCII: chữ cái đầu, tiếp theo chữ/số/_/$
    private static final String IDENTIFIER_REGEX = "^[a-zA-Z_$][a-zA-Z0-9_$]*$";
    
    // Danh sách keyword (Java 17)
    private static final Set KEYWORDS = Set.of(
        "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
        "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float",
        "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
        "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super",
        "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
        "_", "record", "sealed", "non-sealed", "permits", "yield", "module", "open", "opens", "requires",
        "exports", "to", "uses", "provides", "with", "transitive"
    );
    
    public static boolean isValidIdentifier(String str) {
        if (str == null || str.isEmpty()) return false;
        if (!str.matches(IDENTIFIER_REGEX)) return false;
        if (KEYWORDS.contains(str)) return false;
        return true;
    }
    
    public static void main(String[] args) {
        String[] tests = {"validName", "_private", "$dollar", "2invalid", "class", "null", "valid$name123", "tên_việt"};
        for (String t : tests) {
            System.out.printf("%-15s : %s%n", t, isValidIdentifier(t));
        }
    }
}

Cách 2: Character API (Hỗ trợ Unicode chuẩn Java)

public static boolean isValidIdentifierUnicode(String str) {
    if (str == null || str.isEmpty()) return false;
    if (KEYWORDS.contains(str)) return false;
    
    int cp = str.codePointAt(0);
    if (!Character.isJavaIdentifierStart(cp)) return false;
    
    for (int i = Character.charCount(cp); i < str.length(); i += Character.charCount(cp)) {
        cp = str.codePointAt(i);
        if (!Character.isJavaIdentifierPart(cp)) return false;
    }
    return true;
}
  • Character.isJavaIdentifierStart(int codePoint): Kiểm tra ký tự bắt đầu hợp lệ (Unicode Letter, _, $).
  • Character.isJavaIdentifierPart(int codePoint): Kiểm tra ký tự tiếp theo hợp lệ (Letter, Digit, _, $, combining marks...).
  • Xử lý đúng supplementary characters (code point > 0xFFFF) bằng codePointAt và charCount.

Cách 3: Compiler API (Java 9+) – Kiểm tra thực tế

import javax.tools.*;

public static boolean isValidIdentifierCompiler(String name) {
    if (name == null || name.isEmpty()) return false;
    if (KEYWORDS.contains(name)) return false;
    
    // Dùng JavaCompiler để parse một snippet dummy
    String code = "public class Test { void " + name + "() {} }";
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector diagnostics = new DiagnosticCollector<>();
    JavaFileObject file = new SimpleJavaFileObject(URI.create("string:///Test.java"), JavaFileObject.Kind.SOURCE) {
        @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; }
    };
    CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, List.of(file));
    return task.call(); // true nếu compile thành công → identifier hợp lệ
}

So sánh

Kết luận

Dùng Character API cho validation thực tế (hỗ trợ tên tiếng Việt: tên_biến, 変数). Dùng Regex cho validation nhanh, chỉ ASCII. Compiler API chỉ cho tooling/IDE.

CáchƯu điểmNhược điểm
Regex ASCIINhanh, đơn giản, không phụ thuộc JDKKhông hỗ trợ Unicode identifier (tên tiếng Việt, tiếng Nhật...)
Character APIChuẩn Java, hỗ trợ Unicode đầy đủ, nhanhCần JDK runtime
Compiler APIChính xác 100% theo language specNặng, chậm, cần tools.jar (JDK không JRE)