web-dev-qa-db-fra.com

Comment déterminer si un personnage est une lettre en Java?

Comment vérifiez-vous si une chaîne d'un caractère est une lettre - y compris des lettres avec des accents?

Je devais y travailler récemment, alors je vais y répondre moi-même après que la récente question VB6 m'a rappelé.

27
Peter Hilton

Je vérifie juste si une lettre est dans A-Z parce que cela n'inclut pas les lettres avec des accents ou des lettres d'autres alphabets.

J'ai découvert que vous pouvez utiliser la classe d'expression régulière pour "lettre Unicode" ou une de ses variations sensibles à la cas:

string.matches("\\p{L}"); // Unicode letter
string.matches("\\p{Lu}"); // Unicode upper-case letter

Vous pouvez également faire cela avec caractère classe:

Character.isLetter(character);

mais cela est moins pratique si vous avez besoin de vérifier plus d'une lettre.

22
Peter Hilton

Caractère.sletter () est beaucoup plus rapide que String.Matches (), car string.matches () compile un nouveau modèle à chaque fois. Même en cache le motif, je pense que Isletter () la battrait toujours.


éditer : Juste couru à travers cela et pensais que j'essayais d'essayer de trouver des chiffres réels. Voici ma tentative de référence, vérifiant les trois méthodes (matches() avec et sans mettre en cache le Pattern et Character.isLetter()). Je me suis également assuré qu'il y avait des personnages valides et non valides vérifiés, de manière à ne pas incliner de choses.

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));
    }
}

Et ma sortie:

10000000 tests de motif.Matches () a pris 4325146672 NS. [.____] Il y avait 4062500/10000000 caractères valides [.____] 10000000 tests d'Isletter () ont pris 546031201 NS. [.____] Il y avait 4062500/10000000 valide caractères 
 10000000 tests de string.matches () a pris 11900205444 NS. [.____] Il y avait 4062500/10000000 caractères valides

C'est donc presque 8 fois mieux, même avec une mise en cache Pattern. (Et inconnu est presque 3 fois pire que la mise en cache.)

33
Michael Myers