2010-02-07 14 views
18

Tôi stumped cố gắng để tạo ra một biểu thức thường xuyên Emacs mà loại trừ các nhóm. [^] không bao gồm các ký tự riêng lẻ trong một tập hợp, nhưng tôi muốn loại trừ các chuỗi cụ thể của ký tự: một cái gì đó như [^(not|this)], để các chuỗi có chứa "không" hoặc "này" không khớp.Tôi làm cách nào để viết cụm từ thông dụng loại trừ thay vì đối sánh, ví dụ: không phải (chuỗi | này)?

Về nguyên tắc, tôi có thể viết ([^n][^o][^t]|[^...]), nhưng có cách nào khác sạch hơn không?

+3

Tôi nghĩ đó là GNU ERE. – Gumbo

+0

@Gumbo. bạn nói đúng, cảm ơn – Anycorn

+0

Nhấp vào thẻ "regex-negation" để xem một số câu hỏi tương tự. – finnw

Trả lời

13

Trước hết: [^n][^o][^t] không phải là giải pháp. Điều này cũng sẽ loại trừ các từ như nil ([^n] không khớp), bob ([^o] không khớp) hoặc cat ([^t] không khớp).

Nhưng chúng ta có thể xây dựng một biểu thức chính quy với cú pháp cơ bản mà không chuỗi trận đấu mà không chứa not cũng không this:

^([^nt]|n($|[^o]|o($|[^t]))|t($|[^h]|h($|[^i]|i($|[^s]))))*$ 

Các mô hình của biểu thức chính quy này là cho phép bất kỳ nhân vật đó không phải là người đầu tiên ký tự của các từ hoặc chỉ các tiền tố của các từ chứ không phải toàn bộ các từ.

+12

+1 và nếu tôi đã bao giờ bị cám dỗ chuyển sang Emacs thì đây sẽ là lý do không đủ để. Làm thế nào có thể bất cứ ai * sống * mà không có lookaheads? : P –

+1

Được thưởng thức Emacs rất nhiều cho đến nay, đây là lần đầu tiên "những gì ..." – biocyberman

19

Điều này là không dễ dàng. Cụm từ thông dụng được thiết kế để khớp với thứ và đây là tất cả những gì họ có thể làm.

Trước hết: [^] không chỉ định "loại trừ nhóm", nó chỉ định một lớp nhân vật phủ định. Các lớp nhân vật không hỗ trợ nhóm theo bất kỳ hình thức hoặc hình dạng nào. Chúng hỗ trợ các ký tự đơn (và, để thuận tiện, phạm vi ký tự). Thử của bạn [^(not|this)] là 100% tương đương với [^)(|hinots], theo như động cơ regex có liên quan.

Ba cách có thể dẫn ra khỏi tình trạng này:

  1. trận đấu (not|this)loại trừ bất kỳ trận đấu với sự giúp đỡ của môi trường bạn đang ở trong (phủ nhận kết quả trận đấu)
  2. sử dụng tiêu cực nhìn về phía trước, nếu được hỗ trợ bởi công cụ regex của bạn và khả thi trong trường hợp
  3. viết lại biểu thức để nó có thể khớp với: xem a similar question I asked earlier
+1

Tôi tự hỏi tại sao câu trả lời này lại được đánh giá thấp như vậy, đây là câu trả lời rõ ràng nhất ở đây! –

+0

@Yagamy Bởi vì nó nhiều hay ít nói "không hoạt động" trong khi rõ ràng có một cách để làm cho nó hoạt động (mặc dù một không thực tế đó là nhiều hơn một phương sách cuối cùng). – Tomalak

+1

Tôi không thấy ở đây một tuyên bố "Không hoạt động", thậm chí ngược lại: bạn đã cho thấy ba cách có thể giải quyết vấn đề và câu hỏi thứ ba giống như câu trả lời được chấp nhận. –

13

Khó tin rằng câu trả lời được chấp nhận (từ Gumbo) thực sự được chấp nhận! Trừ khi nó được chấp nhận bởi vì nó chỉ ra rằng bạn không thể làm những gì bạn muốn. Trừ khi bạn có một chức năng tạo ra các regexps như (như Gumbo cho thấy), sáng tác chúng sẽ là một nỗi đau thực sự.

Trường hợp sử dụng thực sự là gì - bạn đang thực sự cố gắng làm gì?

Như Tomalak đã chỉ ra, (a) đây không phải là những gì regexp làm; (b) xem bài đăng khác mà anh ta đã liên kết, để có giải thích tốt, bao gồm cả việc cần làm về vấn đề của bạn.

Câu trả lời là sử dụng regexp để khớp với những gì bạn làm không muốn và sau đó trừ số đó khỏi miền ban đầu.IOW, không cố gắng làm cho regexp làm việc không bao gồm (nó không thể); thực hiện việc loại trừ sau bằng cách sử dụng regexp để khớp với những gì bạn muốn loại trừ.

Đây là cách mọi công cụ sử dụng công thức regexps (ví dụ: grep): chúng cung cấp tùy chọn riêng biệt (ví dụ: thông qua cú pháp) thực hiện phép trừ - sau khi khớp với những gì cần được trừ.

6

Có vẻ như bạn đang cố gắng làm những điều không mong muốn tiêu cực. tức là bạn đang cố gắng ngừng kết hợp khi bạn đạt đến một số dấu phân cách.

Emacs không hỗ trợ trực tiếp, nhưng nó hỗ trợ phiên bản không tham lam của *, + và? toán tử (* ?, + ?, ??), có thể được sử dụng cho cùng một mục đích trong hầu hết các trường hợp.

Vì vậy, ví dụ, để phù hợp với cơ thể của hàm javascript này:

bar = function (args) { 
    if (blah) { 
     foo(); 
    } 
}; 

Bạn có thể sử dụng emacs regex:

function ([^)]+) {[[:ascii:]]+?}; 

Ở đây chúng ta đang dừng lại khi chúng tôi tìm ra chuỗi hai yếu tố "};". [[: ascii:]] được sử dụng instad của "." bởi vì nó hoạt động trên nhiều dòng.

Đây là một chút khác biệt so với cái nhìn tiêu cực vì}; trình tự nó khớp với nhau, tuy nhiên nếu mục tiêu của bạn là trích xuất mọi thứ cho đến thời điểm đó, bạn chỉ cần sử dụng nhóm chụp \ (và \).

Xem hướng dẫn emacs regex: http://www.gnu.org/software/emacs/manual/html_node/emacs/Regexps.html

Là một mặt lưu ý, nếu bạn viết bất kỳ loại emacs regex, hãy chắc chắn để gọi Mx tái xây dựng, trong đó sẽ đưa lên một chút IDE để viết regex của bạn chống lại bộ đệm hiện tại.

1

Đối với trường hợp sử dụng phù hợp với một chuỗi cho kiểm tra logic, tôi làm điều này:

;; Code to match string ends with '-region' but excludes those that has 'mouse'. 
M-x ielm RET 
*** Welcome to IELM *** Type (describe-mode) for help. 
ELISP> (setq str1 "mouse-drag-region" str2 "mou-drag-region" str3 "mou-region-drag") 
"mou-region-drag" 
ELISP> (and (string-match-p "-region$" str1) (not (string-match-p "mouse" str1))) 
nil 
ELISP> (and (string-match-p "-region$" str2) (not (string-match-p "mouse" str2))) 
t 
ELISP> (and (string-match-p "-region$" str3) (not (string-match-p "mouse" str3))) 
nil 

tôi sử dụng phương pháp này để tránh những lỗi của hàm tôi đã thảo luận Over Here: