2012-05-09 52 views
16

Tôi có danh sách khoảng 120 nghìn từ tiếng Anh (về cơ bản là mỗi từ trong ngôn ngữ).Biểu thức chính quy Ký tự đại diện

Tôi cần cụm từ thông dụng cho phép tìm kiếm thông qua các từ này bằng ký tự đại diện, a.k.a. *?.

Một vài ví dụ:

  • nếu người dùng tìm kiếm m?st*, nó sẽ phù hợp với ví dụ master hoặc mister hoặc mistery.
  • nếu người dùng tìm kiếm *ind (bất kỳ từ nào kết thúc bằng ind), nó sẽ khớp với wind hoặc bind hoặc blind hoặc grind.

Bây giờ, hầu hết người dùng (đặc biệt là những người không quen thuộc với biểu thức thông thường) biết rằng ? là một sự thay thế cho chính xác 1 nhân vật, trong khi * là một sự thay thế cho 0, 1 hoặc nhiều ký tự. Tôi hoàn toàn muốn xây dựng tính năng tìm kiếm của mình dựa trên điều này.

Câu hỏi của tôi là: Làm cách nào để chuyển đổi những gì người dùng nhập (ví dụ: m?st*) thành cụm từ thông dụng?

Tôi tìm kiếm trên web (rõ ràng bao gồm trang web này) và tất cả những gì tôi có thể tìm thấy là hướng dẫn cố gắng dạy cho tôi quá nhiều hoặc câu hỏi tương tự nhưng không đủ để cung cấp câu trả lời cho vấn đề của riêng tôi.

Tất cả những gì tôi có thể tìm ra là tôi phải thay thế ? bằng .. Vì vậy, m?st* trở thành m.st*. Tuy nhiên, tôi không có ý tưởng gì để thay thế * bằng.

Mọi trợ giúp sẽ được đánh giá cao. Cảm ơn bạn.

PS: Tôi hoàn toàn mới đối với cụm từ thông dụng. Tôi biết họ có thể mạnh mẽ như thế nào, nhưng tôi cũng biết rằng họ có thể rất khó học. Vì vậy, tôi không bao giờ dành thời gian làm cho nó ...

+1

bản sao có thể có của [Có tương đương với java.util.regex cho mẫu kiểu "glob" không?] (Http://stackoverflow.com/questions/1247772/is-there-an-equivalent-of-java- util-regex-for-glob-type-patterns) – NPE

+2

Hãy nhớ rằng bất kỳ * ký tự regex * nào khác có thể xuất hiện trong truy vấn của bạn cũng sẽ phải được thoát. Nếu ai đó gõ vào '^ \ w..' bạn có thể không muốn truyền nó tới công cụ biểu thức thông thường của bạn ở dạng thô của nó – Gareth

+0

@Gareth Cảm ơn bạn, tôi sẽ nhớ điều đó. –

Trả lời

15

Trừ khi bạn muốn có một số hành vi buồn cười, tôi sẽ khuyên bạn sử dụng \w thay vì .

. phù hợp với những biểu tượng không từ khoảng trắng và khác, mà bạn có thể không muốn nó làm.

Vì vậy, tôi sẽ thay thế ? với \w và thay thế * với \w*

Ngoài ra nếu bạn muốn * để phù hợp với ít nhất một nhân vật, thay thế nó với \w+ để thay thế. Điều này có nghĩa là ben* sẽ khớp với bendbending nhưng không phải là ben - tùy thuộc vào bạn, chỉ phụ thuộc vào yêu cầu của bạn là gì.

+0

Câu hỏi nói "trong khi' * 'là một thay thế cho 0, 1 hoặc nhiều ký tự" – Gareth

+2

@Gareth ya, tôi đã thấy điều đó. Chỉ nghĩ rằng tôi sẽ cung cấp thêm thông tin. – gnomed

+0

@gnomed Tại sao '\ w' tốt hơn' .'? –

1

. là một biểu thức khớp với bất kỳ một ký tự nào, như bạn đã khám phá. Trong số giờ tìm kiếm của bạn, chắc chắn bạn cũng đã gặp phải một số nhà điều hành lặp lại khi được sử dụng sau khi biểu thức khớp với biểu thức trước 0 hoặc nhiều lần trong một hàng.

Vì vậy, tương đương với ý nghĩa của bạn là * đang đặt hai giá trị này lại với nhau: .*. Điều này có nghĩa là "bất kỳ ký tự nào không hoặc nhiều lần".

Xem Regex Tutorial on repetition operators.

+0

Vâng, tôi biết, tôi không giỏi tìm kiếm mọi thứ trên web, đặc biệt nếu tôi hoàn toàn xa lạ với họ :). –

1

Thay thế * bằng .* (regex tương đương với "0 trở lên của bất kỳ ký tự nào").

6

Thay thế ? bằng .* với .*.

2
  1. Thay thế tất cả '?' nhân vật với '\ w'
  2. Thay thế tất cả '*' nhân vật với '\ w *'

Các '*' hành lặp đi lặp lại mục trước '' (bất kỳ ký tự nào) 0 hoặc nhiều lần.

Điều này giả định rằng không có từ nào chứa '.', '*' Và '?'.

Đây là một tài liệu tham khảo tốt

http://www.regular-expressions.info/reference.html

0
function matchWild(wild,name) 
{ 
    if (wild == '*') return true; 

    wild = wild.replace(/\./g,'\\.'); 
    wild = wild.replace(/\?/g,'.'); 
    wild = wild.replace(/\\/g,'\\\\'); 
    wild = wild.replace(/\//g,'\\/'); 
    wild = wild.replace(/\*/g,'(.+?)'); 

    var re = new RegExp(wild,'i'); 
    return re.test(name); 
} 
2

Dưới đây là một cách để chuyển đổi ký tự đại diện vào regex:

  1. Thêm vào trước tất cả special characters([{\^- = $! |]}). + với \ - để chúng được so khớp dưới dạng ký tự và không làm cho trải nghiệm người dùng không mong muốn. Ngoài ra, bạn có thể đính kèm trong vòng \ Q (bắt đầu báo giá) và \ E (kết thúc). Cũng xem đoạn về an ninh.
  2. Thay thế * ký tự đại diện bằng \ S *
  3. Thay thế? ký tự đại diện với \ S?
  4. Tùy chọn: mẫu thêm vào với ^ - điều này sẽ thực thi khớp chính xác với phần đầu.
  5. Tùy chọn: nối thêm $ vào mẫu - điều này sẽ thực thi khớp chính xác với kết thúc.

    \ S - đứng cho ký tự không dấu cách, xảy ra không hoặc nhiều lần.

Cân nhắc using reluctant (non-greedy) quantifiers nếu bạn có nhân vật để phù hợp sau * hoặc +. Điều này có thể được thực hiện bằng cách thêm ? sau * hoặc + như sau: \ S *?\ S * +?

Cân nhắc bảo mật: người dùng sẽ gửi cho bạn mã để chạy (vì regex cũng là loại mã và chuỗi người dùng được sử dụng làm regex). Bạn nên tránh bỏ qua regex không thoát khỏi bất kỳ phần nào khác của ứng dụng và chỉ sử dụng để lọc dữ liệu được truy xuất bằng các phương tiện khác. Bởi vì nếu bạn làm người dùng có thể ảnh hưởng đến tốc độ của mã của bạn bằng cách cung cấp regex khác nhau với chuỗi ký tự đại diện - điều này có thể được sử dụng trong các cuộc tấn công DoS.

Ví dụ để hiển thị tốc độ thực hiện các mô hình tương tự:

seq 1 50000000 > ~/1 
du -sh ~/1 
563M 
time grep -P '.*' ~/1 &>/dev/null 
6.65s 
time grep -P '.*.*.*.*.*.*.*.*' ~/1 &>/dev/null 
12.55s 
time grep -P '.*..*..*..*..*.*' ~/1 &>/dev/null 
31.14s 
time grep -P '\S*.\S*.\S*.\S*.\S*\S*' ~/1 &>/dev/null 
31.27s 

tôi muốn đề nghị không nên sử dụng * đơn giản chỉ vì nó có thể phù hợp với bất cứ điều gì, và thường điều được tách bằng dấu cách..

0

Đây là những gì tôi sử dụng:

String wildcardToRegex(String wildcardString) { 
    // The 12 is arbitrary, you may adjust it to fit your needs depending 
    // on how many special characters you expect in a single pattern. 
    StringBuilder sb = new StringBuilder(wildcardString.length() + 12); 
    sb.append('^'); 
    for (int i = 0; i < wildcardString.length(); ++i) { 
     char c = wildcardString.charAt(i); 
     if (c == '*') { 
      sb.append(".*"); 
     } else if (c == '?') { 
      sb.append('.'); 
     } else if ("\\.[]{}()+-^$|".indexOf(c) >= 0) { 
      sb.append('\\'); 
      sb.append(c); 
     } else { 
      sb.append(c); 
     } 
    } 
    sb.append('$'); 
    return sb.toString(); 
} 

đặc biệt danh sách nhân vật từ https://stackoverflow.com/a/26228852/1808989.

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