2009-11-17 19 views
40

Trong thư mục chính của tôi, tôi có một thư mục drupal-6.14 chứa nền tảng Drupal.Biểu hiện chính xác tiêu cực lookahead

Từ thư mục này tôi sử dụng lệnh sau:

find drupal-6.14 -type f -iname '*' | grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' | xargs tar -czf drupal-6.14.tar.gz 

gì lệnh này làm là gzips thư mục drupal-6.14, trừ tất cả các thư mục con của drupal-6.14/trang web/trừ các trang web/tất cả và các trang web/mặc định, bao gồm.

Câu hỏi của tôi là về biểu thức chính quy:

grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' 

Khái niệm làm việc để loại trừ tất cả các thư mục Tôi muốn loại trừ, nhưng tôi hoàn toàn không hiểu tại sao.

Đó là một nhiệm vụ thường sử dụng biểu thức thông thường để

trận đấu tất cả các chuỗi, ngoại trừ những không chứa subpattern x. Hay nói cách khác, phủ nhận một mẫu con.

I (think) Tôi hiểu rằng chiến lược chung để giải quyết những vấn đề này là sử dụng những cái nhìn tiêu cực, nhưng tôi chưa bao giờ hiểu mức độ hài lòng và tiêu cực (trước/sau).

Trong những năm qua, tôi đã đọc nhiều trang web trên chúng. Hướng dẫn sử dụng PHP và Python regex, các trang khác như http://www.regular-expressions.info/lookaround.html và vân vân, nhưng tôi chưa bao giờ thực sự hiểu rõ về chúng.

Ai đó có thể giải thích, làm thế nào điều này đang làm việc, và có lẽ cung cấp một số ví dụ tương tự mà sẽ làm những việc tương tự?

- Cập nhật One:

Về phản ứng Andomar của: có thể một đôi lookahead tiêu cực được ngắn gọn hơn thể hiện dưới dạng một tuyên bố lookahead tích cực duy nhất:

tức là:

'drupal-6.14/(?!sites(?!/all|/default)).*' 

tương đương với:

'drupal-6.14/(?=sites(?:/all|/default)).*' 

???

- Cập nhật thứ hai:

Theo @andomar và @alan moore - bạn không thể trao đổi đôi lookahead tiêu cực đối với lookahead tích cực.

Trả lời

84

Một lookahead tiêu cực nói , tại vị trí này, regex sau không thể khớp.

Hãy lấy một ví dụ đơn giản:

a(?!b(?!c)) 

a  Match: (?!b) succeeds 
ac  Match: (?!b) succeeds 
ab  No match: (?!b(?!c)) fails 
abe No match: (?!b(?!c)) fails 
abc Match: (?!b(?!c)) succeeds 

Ví dụ cuối cùng là một đôi phủ: nó cho phép một b Tiếp theo c. Các lookahead tiêu cực lồng nhau trở thành một lookahead tích cực: c nên có mặt.

Trong mỗi ví dụ, chỉ a được đối sánh. Lookahead chỉ là một điều kiện, và không thêm vào văn bản phù hợp.

+0

Nếu một cái nhìn tiêu cực lồng nhau ("cái nhìn tiêu cực kép") có thể trở thành một cái nhìn tích cực, liệu nó có thể thể hiện trạng thái tương đương ở dạng lookahead dương? i.e: (a) Điều gì sẽ là hình thức lookahead tích cực của drupal tiêu cực kép của tôi drupal "'drupal-6.14/(?! sites (?!/all |/default)). *'" Ví dụ? Có thể là: 'drupal-6.14/(? = Sites/all | default). * ??? (b) Điều gì sẽ là hình thức lookahead tích cực của cái nhìn đôi tiêu cực của bạn "(!? B (?! C))" ví dụ? – themesandmodules

+0

eww. lấy làm tiếc. lần đầu tiên sử dụng bình luận ở đây là định dạng là khủng khiếp. nghỉ ngơi bằng cách chỉnh sửa câu hỏi. – themesandmodules

+0

@willieseabrook: Đừng nghĩ như vậy, chỉ một phần của lookahead là gấp đôi tiêu cực, vì vậy bạn không thể thay thế toàn bộ với một tích cực – Andomar

12

Có thể lồng nhau.

Vì vậy regex này phù hợp "drupal-6.14 /" có nghĩa là không tiếp theo là "các trang web" đó là không tiếp theo là "/ all" hoặc "/ default".

Khó hiểu?Sử dụng các từ khác nhau, chúng ta có thể nói rằng nó phù hợp với "drupal-6.14 /" có nghĩa là không tiếp theo là "các trang web" trừ đó là tiếp tục tiếp theo là "/ all" hoặc "/ default"

+0

Cảm ơn vì điều này. Và * có * Tôi vẫn thấy nó khó hiểu LOL. Tôi nghĩ bạn đang báo giá "không theo sau bởi các trang web * trừ khi * theo sau là tất cả | mặc định" khá hữu ích. – themesandmodules

1

Nếu bạn sửa đổi biểu thức chính quy của bạn như thế này:

drupal-6.14/(?=sites(?!/all|/default)).* 
      ^^ 

... sau đó nó sẽ phù hợp với tất cả các đầu vào có chứa drupal-6.14/ tiếp theo sites tiếp theo bất cứ điều gì khác hơn là/all hoặc /default. Ví dụ:

drupal-6.14/sites/foo 
drupal-6.14/sites/bar 
drupal-6.14/sitesfoo42 
drupal-6.14/sitesall 

Thay đổi ?= để ?! để phù hợp với regex ban đầu của bạn chỉ đơn giản là phủ nhận những trận đấu:

drupal-6.14/(?!sites(?!/all|/default)).* 
      ^^ 

Vì vậy, điều này chỉ đơn giản có nghĩa là drupal-6.14/ tại không thể được theo sau bởi sites tiếp theo bất cứ điều gì khác hơn/all hoặc /default. Vì vậy, bây giờ, những đầu vào sẽ làm hài lòng các regex:

drupal-6.14/sites/all 
drupal-6.14/sites/default 
drupal-6.14/sites/all42 

Nhưng, những gì có thể không rõ ràng từ một số các câu trả lời khác (và có thể câu hỏi của bạn) là regex của bạn cũng sẽ cho phép đầu vào khác nơi drupal-6.14/ được theo sau bởi bất kỳ điều gì khác ngoài sites. Ví dụ:

drupal-6.14/foo 
drupal-6.14/xsites 

Kết luận: Vì vậy, regex của bạn về cơ bản nói để bao gồm tất cả thư mục con của drupal-6.14trừ những thư mục con của sites có tên bắt đầu với bất cứ điều gì khác hơn là all hoặc default.