2013-08-04 41 views
8

Tôi có danh sách các từ khóa được nhập vào bởi người sử dụng và họ có thể chứa các ký tự đặc biệt như $, #, @, ^, &,, vvJava Regular Expression to Match Lời Chính xác Chứa kí tự đặc biệt

Theo yêu cầu của tôi khi bao giờ tôi nhận được danh sách các tin nhắn văn bản i cần phải tìm kiếm tất cả các từ khóa trong mỗi thư.

Chúng tôi cần phải đối sánh chính xác từ khóa.

TRƯỜNG HỢP 1: Đơn giản theo từ khóa - Tin Simple

tôi đã sử dụng \b để phù hợp với từ khóa chính xác và nó làm việc tốt.

public static void main(String[] args) { 
     String patternStr = "(?i)\\bHello\\b"; 

     Pattern pattern = Pattern.compile(patternStr); 

     List<String> strList = new ArrayList<String>(); 
     strList.add("HHello Message"); 
     strList.add("This is Hello Message "); 
     strList.add("Now Hellos again."); 

     for(String str : strList) { 
      Matcher matcher = pattern.matcher(str); 
      System.out.println(">> "+matcher.find()); 
     } 
    } 

OUTPUT như dự kiến ​​

>> false 
>> true 
>> false 

TRƯỜNG HỢP 2: từ khóa đơn giản - nhắn với nhân vật đặc biệt

Bây giờ, nếu tôi chạy trên cùng một mã cho thông điệp sau đây thì nó không hoạt động như mong đợi.

List<String> strList = new ArrayList<String>(); 
strList.add("#Hello Message"); 
strList.add("This is Hello Message "); 
strList.add("Now Hellos again."); 

OUTPUT:

true 
true 
false 

Dự kiến ​​OUTPUT

false 
true 
false 

TRƯỜNG HỢP 3: Keyword & nhắn với nhân vật đặc biệt

Nếu tôi nhận được các tin nhắn sau và từ khóa là #Hello. Tôi đã viết mã sau nhưng nó không hoạt động.

public static void main(String[] args) { 
     String patternStr = "(?i)\\b#Hello\\b"; 

     Pattern pattern = Pattern.compile(patternStr); 

     List<String> strList = new ArrayList<String>(); 
     strList.add("HHello Message"); 
     strList.add("This is #Hello Message "); 
     strList.add("Now Hellos again."); 

     for(String str : strList) { 
      Matcher matcher = pattern.matcher(str); 
      System.out.println(">> "+matcher.find()); 
     } 
    } 

OUTPUT:

>> false 
>> false 
>> false 

Dự kiến ​​OUTPUT:

>> false 
>> true 
>> false 

Làm thế nào tôi có thể thoát khỏi nhân vật đặc biệt và giải quyết CASE 2 and CASE 3.

Vui lòng trợ giúp.

+1

Ranh giới từ không có nghĩa là ranh giới không gian. Đây là nơi bạn đang bối rối. – tchrist

Trả lời

3

Trường hợp 2 có vẻ ngược lại với trường hợp 3, vì vậy tôi không nghĩ rằng bạn có thể kết hợp số Pattern s.

Đối với trường hợp 2, Pattern của bạn có thể trông giống như:

Pattern pattern = Pattern.compile("(\\s|^)Hello(\\s|$)", Pattern.CASE_INSENSITIVE); 

Trong trường hợp này chúng ta bao quanh các từ khóa bằng khoảng trắng hoặc đầu/cuối đầu vào.

Đối với trường hợp 3, Pattern của bạn có thể trông giống như:

Pattern pattern = Pattern.compile("[\\$#@\\^&]Hello(\\s|$)", Pattern.CASE_INSENSITIVE); 

Trong trường hợp này, chúng tôi đặt trước từ khóa với bất kỳ ký tự đặc biệt của sự lựa chọn của bạn (chú ý thoát reserved ký tự $^), sau đó chúng tôi chấp nhận khoảng trắng hoặc phần cuối của đầu vào là ký tự theo từ khóa.

+0

Tôi kết hợp cả hai mẫu như sau Pattern.compile ("(\\ s | ^)" + Pattern.quote (cụm từ) + "(\\ s | $)", Pattern.CASE_INSENSITIVE); va no đa hoạt động !!! –

2

Sử dụng (?:^|\s) ("khởi đầu của văn bản hoặc khoảng trắng") thay vì các \b đầu tiên, và (?:$|\s) ("kết thúc của văn bản hoặc khoảng trắng") thay vì thứ hai \b trong regex của bạn.

+0

Cảm ơn lời giải thích –

1

Sự cố xuất phát từ cách "từ chính xác" được xác định. Nó không chỉ là khoảng trắng có thể bao quanh từ để biến nó thành một từ. Ví dụ trong hầu hết các trường hợp, người ta muốn một từ khớp chính xác cho 'Hello' để làm việc.

"xin chào", "Người đàn ông trẻ đó vừa chào hỏi người đàn ông trẻ kia" và "tôi ước mọi người sẽ vẫn trả lời điện thoại bằng cách nói ahoy thay vì Xin chào".

Nếu bạn muốn đối sánh chỉ được chia thành khoảng trắng thì tôi tin rằng bạn sẽ phải chỉ định điều kiện khoảng trắng. Giả sử bạn cũng muốn nó để phù hợp ở cuối sau đó tôi sẽ đề xuất một cái gì đó như thế này.

Pattern pattern = Pattern.compile("\(^\| \)" + escapeSearchString(patternString) + "\(\|$\)"); 

và sau đó có một vài phương pháp như thế này

public String escapeSearchString(String patternString) { 
    StringBuilder stringBuilder = new StringBuilder(patternString.length() * 3); 
    for (char c : patternString.toCharArray()) { 
     if (isEscapableCharacter(c)) { 
      stringBuilder.append("\\"); 
     } 
     stringBuilder.append(c); 
    } 
} 

public boolean isEscapableCharacter(char c) { 
    switch (c) { 
     case '#': 
     case '$': 
     case '@': 
     case '^': 
     case '&': 
      return true; 
     default: 
      return false; 
    } 
} 

Nó có lẽ sẽ tốt hơn để lặp qua một char [] cho các nhân vật escapable và tải chúng từ một tập tin cấu hình.

1

Cố gắng có lẽ cách này

String patternStr = "(?i)(?<=\\s|^)"+Pattern.quote(searchedStubstring)+"(?=\\s|$)"; 

(? < = ...) và (? = ...) là dương look behind and ahead vì vậy nó sẽ kiểm tra xem trước searchedStubstring của bạn sẽ có

  • white-space \\s hoặc bắt đầu của đầu vào ^ trước đây và
  • white-space \\s hoặc kết thúc đầu vào & sau đó.

Cũng trong trường hợp bạn muốn tìm kiếm cho các ký tự đặc biệt như $+ và những người khác bạn cần phải thoát khỏi chúng.Để thực hiện điều này, bạn có thể sử dụng Pattern.quote(searchedStubstring)

0

ví dụ nếu từ bạn muốn có char đặc biệt (ví dụ ở đây '#') vào lúc bắt đầu và kết thúc của điều này, bạn phải viết như sau:

Pattern p = Pattern.compile("(\\s|^|#)"+word+"(\\s|\\#|$)", Pattern.CASE_INSENSITIVE); 

nếu bạn muốn đối sánh chính xác:

Pattern p = Pattern.compile("(\\s|^)"+word+"(\\s|$)", Pattern.CASE_INSENSITIVE); 

bằng '|' là như OR, do đó bạn có thể thêm bao trận đấu đặc biệt char của bạn muốn ví dụ ..for:

Pattern p = Pattern.compile("(\\s|^|#|:|-)"+word+"(\\s|\\#|\\,|\\.|$)", Pattern.CASE_INSENSITIVE); 

char '^' có nghĩa là để phát hiện các chuỗi ở đầu dòng và '$' có nghĩa là ở cuối dòng. xem thêm tại đây: Summary of regular-expression constructs

Các vấn đề liên quan