2012-01-27 26 views
17

Tôi đang cố gắng sử dụng lookbehinds trong một biểu thức chính quy và nó dường như không hoạt động như tôi mong đợi. Vì vậy, đây không phải là cách sử dụng thực sự của tôi, nhưng để đơn giản hóa tôi sẽ đưa ra một ví dụ. Hãy tưởng tượng tôi muốn khớp "ví dụ" trên một chuỗi có nội dung "đây là một ví dụ". Vì vậy, theo sự hiểu biết của tôi về lookbehinds này nên làm việc:Regular Expression Lookbehind không hoạt động với các định lượng ('+' hoặc '*')

(?<=this\sis\san\s*?)example 

Điều này nên làm là tìm thấy "đây là một", sau đó ký tự không gian và cuối cùng là phù hợp với từ "example". Bây giờ, nó không hoạt động và tôi không hiểu tại sao, là nó không thể sử dụng '+' hoặc '*' bên trong lookbehinds?

Tôi cũng đã cố gắng hai và họ làm việc một cách chính xác, nhưng không đáp ứng nhu cầu của tôi:

(?<=this\sis\san\s)example 
this\sis\san\s*?example 

Tôi đang sử dụng trang web này để kiểm tra biểu thức thông thường của tôi: http://gskinner.com/RegExr/

+5

này cần một thẻ nhận dạng ngôn ngữ hoặc môi trường nơi bạn sử dụng chúng. Các biểu thức chính quy của .NET xử lý vấn đề này mà không có vấn đề gì. – Joey

+0

Thông báo! Nếu regex của bạn sẽ hoạt động như bạn muốn nó cũng sẽ khớp với 'example' từ đây:' this is anexample'. Vì vậy, nếu bạn không muốn rằng bạn nên loại bỏ '?' – noob

+0

micha: Chúng có lẽ chỉ cần thay đổi * thành một '+'. Việc loại bỏ '?' Không có hiệu lực trong vấn đề đó. Nhưng thực sự, '*? 'Như một định lượng là vô ích và không cần thiết trong trường hợp này vì không còn khoảng trắng nào khớp với nhau nữa, vì vậy' \ s *? 'Tương đương với' \ s * '. – Joey

Trả lời

15

Nhiều thư viện biểu thức chính quy làm chỉ cho phép biểu nghiêm ngặt để được sử dụng trong cái nhìn đằng sau khẳng định như:

  • chỉ phù hợp với chuỗi độ dài cố định giống nhau: (?<=foo|bar|\s,\s) (ba nhân vật từng)
  • chỉ phù hợp với chuỗi độ dài cố định: (?<=foobar|\r\n) (mỗi chi nhánh với chiều dài cố định)
  • chỉ trận đấu dây với chiều dài ràng buộc trên: (?<=\s{,4}) (lên đến bốn lần lặp lại)

Lý do cho những giới hạn này chủ yếu là do các thư viện đó không thể xử lý các cụm từ thông dụng ngược ở tất cả hoặc chỉ một tập con giới hạn.

Một lý do khác có thể là tránh các tác giả xây dựng các cụm từ thông dụng quá phức tạp, quá nặng để xử lý vì chúng có tên gọi là pathological behavior (xem thêm ReDoS).

Xem thêm section about limitations of look-behind assertions trên Regular-Expressions.info.

+0

Trong [câu trả lời của tôi cho câu hỏi này] (https://stackoverflow.com/questions/17286667/regular-expression-using-negative-lookbehind-not -working-in-notepad/48727748 # 48727748), tôi đã liệt kê một số chiến lược/cách giải quyết sau khi tôi gặp phải hạn chế này đối với các ngoại hình tiêu cực. Hy vọng nó có thể giúp một số người khác quá! – Marathon55

0

Hầu hết các động cơ regex don' t hỗ trợ các biểu thức độ dài biến cho các xác nhận lookbehind.

+1

Nó chỉ là cái nhìn có vấn đề. Lookahead có thể là bất cứ thứ gì trong tất cả các động cơ regex hỗ trợ nó. – Joey

+0

@ Thực tế, được chỉnh sửa để có độ chính xác cao hơn. :) – Amber

3

gì Amber nói là đúng, nhưng bạn có thể làm việc xung quanh nó với cách tiếp cận khác: Một dấu ngoặc đơn không chụp nhóm

(?<=this\sis\san)(?:\s*)example 

Đó làm cho nó một chiều dài cố định nhìn về phía sau, vì vậy nó sẽ làm việc.

+1

Giống như '(? <= This \ sis \ san) \ s *? Example' có nghĩa là nó cũng khớp với khoảng trắng và thông tin của bạn' (?: '') 'Làm cho quá trình chậm hơn. – noob

+0

micha, tôi sẽ lo lắng nhiều hơn về phần phù hợp trong trường hợp đó hơn là về hiệu suất. Tôi nhận được trung bình 0,02451781 ms với nhóm không có khả năng chịu trách nhiệm và 0,02370844 ms mà không có nó. Tôi không nghĩ đó là một sự khác biệt đáng kể. – Joey

+1

@micha No. Nó không giống nhau. Đó là nhóm * không chụp *. Regex của tôi chỉ khớp với 'ví dụ' (không có khoảng trắng phía trước), nhưng ví dụ của bạn * bao gồm * không gian hàng đầu – Bohemian

9

Hey nếu bạn không sử dụng biến python nhìn phía sau xác nhận bạn có thể lừa động cơ regex bằng cách thoát khỏi trận đấu và bắt đầu lại bằng cách sử dụng \K.

Trang web này giải thích nó cũng .. http://www.phpfreaks.com/blog/pcre-regex-spotlight-k ..

Nhưng khá nhiều khi bạn có một biểu hiện mà bạn kết hợp và bạn muốn để có được tất cả mọi thứ đằng sau nó sử dụng \ K sẽ buộc nó phải bắt đầu lại một lần nữa ...

Ví dụ:

string = '<a this is a tag> with some information <div this is another tag > LOOK FOR ME </div>' 

phù hợp với /(\<a).+?(\<div).+?(\>)\K.+?(?=\<div)/ sẽ khiến regex để khởi động lại sau khi bạn phù hợp với kết thúc div thẻ nên regex sẽ không bao gồm trong kết quả. Các (?=\div) sẽ làm cho động cơ có được tất cả mọi thứ ở phía trước của kết thúc thẻ div

+1

hoạt động với ruby ​​2.x nhưng không thành công với 1.9 và jruby 1.7.x; bình luận ban đầu: tốt nhất, tôi ngạc nhiên tôi không bao giờ biết tính năng này. Tìm hiểu để định dạng mã trong trình chỉnh sửa và bạn sẽ vô giá – akostadinov

+0

'\ K' thực sự hữu ích! Không biết tôi sẽ làm gì nếu không có nó ... –

0

Bạn có thể sử dụng biểu thức con.

(this\sis\san\s*?)(example) 

Vì vậy, để lấy nhóm 2, "ví dụ", $2 cho regex, hoặc \2 nếu bạn đang sử dụng một chuỗi định dạng (như cho python của re.sub)

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