TL; DR Đối với chuỗi con đơn giản là tốt nhất nhưng đối với chỉ phù hợp với toàn bộ các từ Regular Expression có lẽ tốt hơn.
Cách tốt nhất để xem phương pháp nào hiệu quả hơn là kiểm tra phương pháp đó.
Bạn có thể sử dụng String.contains()
thay vì String.indexOf()
để đơn giản hóa mã không phải regexp của bạn.
Để tìm kiếm các từ khác nhau Regular Expression trông như thế này:
apple|orange|pear|banana|kiwi
Các |
công trình như một OR
trong Regular Expressions.
mã kiểm tra rất đơn giản của tôi trông như thế này:
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");
}
}
Các kết quả tôi nhận được là như sau:
Contains took 5962ms
Regular Expression took 63475ms
Rõ ràng timings sẽ thay đổi tùy theo số lượng từ được tìm kiếm và Các chuỗi được tìm kiếm, nhưng dường như nhanh hơn 10 lần so với các cụm từ thông dụng cho một tìm kiếm đơn giản như thế này.
Bằng cách sử dụng biểu thức chính quy để tìm kiếm chuỗi bên trong chuỗi khác, bạn đang sử dụng búa tạ để bẻ khóa đai ốc vì vậy tôi đoán chúng ta không nên ngạc nhiên vì nó chậm hơn. Lưu biểu thức chính quy khi các mẫu bạn muốn tìm phức tạp hơn.
Một trường hợp bạn có thể muốn sử dụng Regular Expressions là nếu indexOf()
và sẽ không thực hiện công việc vì bạn chỉ muốn để phù hợp với toàn bộ từ và không chỉ chuỗi con, ví dụ bạn muốn khớp với pear
nhưng không khớp với spears
. Biểu thức chính quy xử lý trường hợp này tốt khi chúng có khái niệm là word boundaries.
Trong trường hợp này, chúng tôi muốn thay đổi mô hình của chúng tôi để:
\b(apple|orange|pear|banana|kiwi)\b
Các \b
nói với chỉ phù hợp với đầu hoặc cuối của một từ và nhóm ngoặc OR biểu thức với nhau.
Lưu ý, khi xác định mô hình này trong mã của bạn, bạn cần phải thoát khỏi dấu xồ nguợc với dấu chéo ngược khác:
Pattern p = Pattern.compile("\\b(apple|orange|pear|banana|kiwi)\\b");
Bạn không thể đọc được? Tôi chưa bao giờ nói nó hiệu quả. –
Hiệu suất phụ thuộc vào độ dài regex. Nếu nó nhỏ hơn 1000 ký tự, hãy tiếp tục. Nếu nó còn bạn cần giải pháp khác. Ví dụ: tách văn bản để tách các từ và kiểm tra chúng dựa vào bảng băm được xác định trước/tập các từ "đã biết". – AlexR
@deporter mục đích của câu trả lời là đưa ra một gợi ý tốt về cách giải quyết câu hỏi không cung cấp một giải pháp hoàn hảo, sáng bóng, đẳng cấp thế giới. Nó có thể dễ dàng được cải thiện và cho khả năng đọc, nếu bạn có 200 chuỗi (một lý do nữa không sử dụng regexp cho điều đó), bạn có thể sử dụng vòng lặp for và nối trong một 'StringBuilder'. Tôi nghĩ rằng câu trả lời của tôi cung cấp đủ hương vị. –