2008-09-18 14 views

Odpowiedz

22

Wystarczy sprawdzić, czy litera jest w A-Z, ponieważ nie zawiera ona liter z akcentami lub liter w innych alfabetach.

I okazało się, że można użyć zwykłej klasy ekspresyjną dla „pisma Unicode” lub jedną z jej odmian wielkość liter:

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

można też zrobić to z Charakter Klasa:

Character.isLetter(character); 

ale jest to mniej wygodne, jeśli trzeba sprawdzić więcej niż jedną literę.

33

Character.isLetter() jest znacznie szybszy niż string.matches(), ponieważ string.matches() kompiluje nowy wzorzec za każdym razem. Nawet buforując wzorzec, myślę, że isLetter() nadal by go pobił.


EDIT: Wystarczy biegł to jeszcze raz i pomyślałem, że starają się wymyślić kilka liczb rzeczywistych. Oto moja próba testu porównawczego, sprawdzająca wszystkie trzy metody (bez buforowania wartości Pattern i Character.isLetter()). Upewniłem się też, że sprawdzane są zarówno poprawne, jak i nieprawidłowe znaki, aby nie przekręcić rzeczy.

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

I moje wyjście:

10000000 tests of Pattern.matches() took 4325146672 ns. 
There were 4062500/10000000 valid characters 
10000000 tests of isLetter() took 546031201 ns. 
There were 4062500/10000000 valid characters 
10000000 tests of String.matches() took 11900205444 ns. 
There were 4062500/10000000 valid characters

Więc to prawie 8x lepiej, nawet z pamięci podręcznej Pattern. (I uncached jest prawie 3 razy gorszy niż buforowany).

+3

Powinieneś użyć 'c.codePointAt (0)' zamiast 'c.charAt (0)' w 'testCharacter()'; w przeciwnym razie nie uda się postaciom spoza BMP. –