TL; DR W przypadku prostych podciągi jest najlepszy, ale dla tylko dopasowanie całych słów Wyrażenie regularne jest prawdopodobnie lepsze.
Najlepszym sposobem sprawdzenia, która metoda jest bardziej wydajna, jest jej przetestowanie.
Możesz użyć String.contains()
zamiast String.indexOf()
, aby uprościć swój kod nieregexp.
Aby szukać różnych słów wyrażenie regularne wygląda następująco:
apple|orange|pear|banana|kiwi
W |
pracuje jako OR
w wyrażeniach regularnych.
My bardzo prosty kod testowy wygląda następująco:
public class TestContains {
private static String containsWord(Set<String> words,String sentence) {
for (String word : words) {
if (sentence.contains(word)) {
return word;
}
}
return null;
}
private static String matchesPattern(Pattern p,String sentence) {
Matcher m = p.matcher(sentence);
if (m.find()) {
return m.group();
}
return null;
}
public static void main(String[] args) {
Set<String> words = new HashSet<String>();
words.add("apple");
words.add("orange");
words.add("pear");
words.add("banana");
words.add("kiwi");
Pattern p = Pattern.compile("apple|orange|pear|banana|kiwi");
String noMatch = "The quick brown fox jumps over the lazy dog.";
String startMatch = "An apple is nice";
String endMatch = "This is a longer sentence with the match for our fruit at the end: kiwi";
long start = System.currentTimeMillis();
int iterations = 10000000;
for (int i = 0; i < iterations; i++) {
containsWord(words, noMatch);
containsWord(words, startMatch);
containsWord(words, endMatch);
}
System.out.println("Contains took " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
matchesPattern(p,noMatch);
matchesPattern(p,startMatch);
matchesPattern(p,endMatch);
}
System.out.println("Regular Expression took " + (System.currentTimeMillis() - start) + "ms");
}
}
Wyniki dostałem były następujące:
Contains took 5962ms
Regular Expression took 63475ms
Oczywiście czasy będą się różnić w zależności od liczby słów poszukiwany i Przeszukiwane ciągi znaków, ale wydaje się być ~ 10 razy szybsze od wyrażeń regularnych dla prostego wyszukiwania, takiego jak to.
Używając Wyrażeń regularnych do wyszukiwania Ciągów w innym Łańcuchu używasz młota do złamania nakrętki, więc myślę, że nie powinniśmy być zaskoczeni, że jest wolniej. Zapisz wyrazy regularne, gdy wzory, które chcesz znaleźć, są bardziej złożone.
jeden przypadek, w którym możesz użyć wyrażeń regularnych jest jeśli indexOf()
i nie będzie wykonać zadanie, ponieważ chcesz tylko dopasować całe słowa a nie tylko podciągi, na przykład chcesz dopasować pear
, ale nie spears
. Wyrażenia regularne obsługują ten przypadek, ponieważ mają one koncepcję word boundaries.
W tym przypadku chcemy zmienić nasz wzór do:
\b(apple|orange|pear|banana|kiwi)\b
\b
mówi tylko dopasować początek lub koniec słowa i grupę wsporniki razem lub wyrażenia.
Uwaga, przy definiowaniu tego wzoru w kodzie trzeba uciec backslashy z innym backslashem:
Pattern p = Pattern.compile("\\b(apple|orange|pear|banana|kiwi)\\b");
Nie możesz po prostu przeczytać? Nigdy nie powiedziałem, że to było wydajne. –
Wydajność zależy od długości regex. Jeśli ma mniej niż 1000 znaków, przejdź do niego. Jeśli będzie dłuższy, potrzebujesz innego rozwiązania. Na przykład podziel tekst na osobne wyrazy i sprawdź je względem wcześniej zdefiniowanej tabeli mieszania/zestawu "znanych" słów. – AlexR
@deporter celem odpowiedzi jest wskazanie, jak rozwiązać pytanie, aby nie zapewnić doskonałego, lśniącego, światowej klasy rozwiązania. Można go łatwo poprawić, a jeśli chodzi o czytelność, jeśli masz 200 ciągów znaków (jeszcze jeden powód, aby nie używać do tego wyrażeń regularnych), możesz użyć pętli for i połączyć się w 'StringBuilder'. Myślę, że moja odpowiedź zapewnia wystarczająco dużo smaku. –