如何在Java中确定一个字符是否为字母?

27

如何检查一个只有一个字符的字符串是否是字母,包括带有重音符号的任何字母?

最近我也曾需要解决这个问题,所以在最近的VB6问题提醒下,我会自己回答。

2个回答

33

Character.isLetter()string.matches()快得多,因为string.matches()每次都要编译新的正则表达式。即使缓存了模式,我认为isLetter()仍然能够胜过它。


编辑:再次遇到这个问题,想试着给出一些实际的数据。以下是我的基准测试,检查所有三种方法(带有和不带有缓存Patternmatches(),以及Character.isLetter())。我还确保对有效字符和无效字符进行了检查,以免影响结果。

import java.util.regex.*;

class TestLetter {
    private static final Pattern ONE_CHAR_PATTERN = Pattern.compile("\\p{L}");
    private static final int NUM_TESTS = 10000000;

    public static void main(String[] args) {
        long start = System.nanoTime();
        int counter = 0;
        for (int i = 0; i < NUM_TESTS; i++) {
            if (testMatches(Character.toString((char) (i % 128))))
                counter++;
        }
        System.out.println(NUM_TESTS + " tests of Pattern.matches() took " +
                (System.nanoTime()-start) + " ns.");
        System.out.println("There were " + counter + "/" + NUM_TESTS +
                " valid characters");
        /*********************************/
        start = System.nanoTime();
        counter = 0;
        for (int i = 0; i < NUM_TESTS; i++) {
            if (testCharacter(Character.toString((char) (i % 128))))
                counter++;
        }
        System.out.println(NUM_TESTS + " tests of isLetter() took " +
                (System.nanoTime()-start) + " ns.");
        System.out.println("There were " + counter + "/" + NUM_TESTS +
                " valid characters");
        /*********************************/
        start = System.nanoTime();
        counter = 0;
        for (int i = 0; i < NUM_TESTS; i++) {
            if (testMatchesNoCache(Character.toString((char) (i % 128))))
                counter++;
        }
        System.out.println(NUM_TESTS + " tests of String.matches() took " +
                (System.nanoTime()-start) + " ns.");
        System.out.println("There were " + counter + "/" + NUM_TESTS +
                " valid characters");
    }

    private static boolean testMatches(final String c) {
        return ONE_CHAR_PATTERN.matcher(c).matches();
    }
    private static boolean testMatchesNoCache(final String c) {
        return c.matches("\\p{L}");
    }
    private static boolean testCharacter(final String c) {
        return Character.isLetter(c.charAt(0));
    }
}

我的输出:

Pattern.matches()的10000000个测试耗时4325146672纳秒。
有4062500/10000000个有效字符。
isLetter()的10000000个测试耗时546031201纳秒。
有4062500/10000000个有效字符。
String.matches()的10000000个测试耗时11900205444纳秒。
有4062500/10000000个有效字符。

所以即使使用缓存的Pattern,速度也提高了近8倍。(而未缓存的速度比缓存还慢近3倍。)


3
testCharacter()中,你应该使用c.codePointAt(0)而不是c.charAt(0);否则它将无法处理超出BMP范围的字符。 - Mechanical snail

22

我只是想确认一个字母是否在A-Z之间,因为这并不包括带有重音符号的字母或其他字母表中的字母。

我发现可以使用正则表达式类来匹配“Unicode字母”或其区分大小写的变体之一:

string.matches("\\p{L}"); // Unicode letter
string.matches("\\p{Lu}"); // Unicode upper-case letter
您也可以使用Character类来完成此操作:
Character.isLetter(character);

但是如果你需要检查多个字母,这样就不太方便了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接