sự khác biệt giữa là gì?:,?! và? = trong regex?


106

Tôi đã tìm kiếm ý nghĩa của những cụm từ này nhưng không thể hiểu sự khác biệt chính xác giữa chúng. Đây là những gì họ nói:

  • ?: Phù hợp với biểu thức nhưng không nắm bắt nó.
  • ?= Khớp một hậu tố nhưng loại trừ nó khỏi chụp.
  • ?! So khớp nếu hậu tố vắng mặt.

Tôi đã thử sử dụng chúng trong RegEx đơn giản và nhận được kết quả tương tự cho tất cả. Ví dụ: 3 biểu thức sau đây cho kết quả rất giống nhau.

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*

Vui lòng cho chúng tôi xem trường hợp thử nghiệm của bạn. Chúng không nên cho kết quả giống nhau.
Bergi

@ sepp2k, nó cũng cho kết quả tương tự trong một số ít trường hợp, một trong số chúng được đề cập trong câu hỏi.
RK Poddar

@Bergi, tôi đã thử nghiệm nó với dữ liệu ngẫu nhiên, chứa các từ tiếng Anh, số điện thoại, url, địa chỉ e-mail, số, v.v.
RK Poddar vào

4
@RKAgarwal Ah, tôi hiểu bạn đã làm gì ở đó. Bạn đã thêm một *sau các nhóm, vì vậy chúng chỉ bị bỏ qua.
sepp2k

ghi chú noobie : bạn chỉ sử dụng chúng khi bắt đầu dấu ngoặc đơn và dấu ngoặc đơn tạo thành một nhóm thu giữ (các bộ dấu ngoặc đơn khác nhau trích xuất các phần khác nhau của văn bản).
Ryan Taylor

Câu trả lời:


150

Sự khác biệt giữa ?=?!là cái trước yêu cầu biểu thức đã cho phải khớp và cái sau yêu cầu nó không khớp. Ví dụ: a(?=b)sẽ khớp với "a" trong "ab", nhưng không khớp với "a" trong "ac". Trong khi đó a(?!b)sẽ khớp với "a" trong "ac", nhưng không khớp với "a" trong "ab".

Sự khác biệt giữa ?:?=?=loại trừ biểu thức khỏi toàn bộ đối sánh trong khi ?:chỉ không tạo nhóm chụp. Vì vậy, ví dụ a(?:b)sẽ khớp với "ab" trong "abc", trong khi a(?=b)sẽ chỉ khớp với "a" trong "abc". a(b)sẽ khớp với "ab" trong "abc" tạo một bản chụp có chứa "b".


78
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

Vui lòng kiểm tra tại đây: http://www.regular-expressions.info/lookaround.html để có hướng dẫn và ví dụ rất tốt về lookahead trong biểu thức chính quy.


15
Tuy nhiên, JavaScript không biết nhìn sau.
Bergi

1
Cái này hoàn thiện hơn cho regex chung.
Yan Yang

/ (? <= ^ a) b / đã làm việc cho tôi trong javascript! Dường như không có hướng dẫn tìm hiểu về Javascript trên internet.
Y. Yoshii

Chỉ các phiên bản trình duyệt gần đây mới bắt đầu hỗ trợ xem lại trong JS
anubhava

- anubhava Tôi không biết bất kỳ sự thay thế nào cho / (? <= ^ A) b / sử dụng biểu thức chính quy thuần túy. Có lẽ tôi có thể nhưng tôi sẽ phải dựa vào các hàm gọi lại.
Y. Yoshii

21

Để hiểu rõ hơn, hãy áp dụng ba biểu thức cộng với một nhóm nắm bắt và phân tích từng hành vi.

  • () nhóm chụp - regex bên trong dấu ngoặc đơn phải được khớp và khớp tạo ra một nhóm chụp
  • (?:) không bắt nhóm - regex bên trong dấu ngoặc đơn phải được khớp nhưng không tạo nhóm bắt
  • (?=) tích cực nhìn về phía trước - khẳng định rằng regex phải phù hợp
  • (?!) tiêu cực nhìn về phía trước - khẳng định rằng không thể so sánh với regex

Hãy áp dụng q(u)iđể bỏ . qkhớp với q và nhóm bắt ukhớp với u . Trận đấu bên trong nhóm bắt được thực hiện và nhóm bắt được tạo. Vì vậy, động cơ tiếp tục với i. Và isẽ phù hợp với tôi . Nỗ lực đối sánh cuối cùng này đã thành công. qui được khớp và một nhóm bắt với u được tạo.

Hãy áp dụng q(?:u)iđể bỏ . Một lần nữa, qkhớp với q và nhóm không bắt ukhớp với u . Đối sánh từ nhóm không chụp được thực hiện, nhưng nhóm chụp không được tạo. Vì vậy, động cơ tiếp tục với i. Và isẽ phù hợp với tôi . Nỗ lực đối sánh cuối cùng này đã thành công. qui được kết hợp

Hãy áp dụng q(?=u)iđể bỏ . Nhìn trước là tích cực và được theo sau bởi một mã thông báo khác. Một lần nữa, qkhớp với qukhớp với u . Một lần nữa, kết quả phù hợp từ lookahead phải bị loại bỏ, do đó, động cơ lùi từ itrong chuỗi sang u . Nhìn trước đã thành công, vì vậy động cơ tiếp tục với i. Nhưng ikhông thể phù hợp với u . Vì vậy, nỗ lực đối sánh này không thành công.

Hãy áp dụng q(?=u)uđể bỏ . Nhìn trước là tích cực và được theo sau bởi một mã thông báo khác. Một lần nữa, qkhớp với qukhớp với u . Kết quả phù hợp từ lookahead phải bị loại bỏ, do đó, động cơ lùi từ utrong chuỗi sang u . Nhìn trước đã thành công, vì vậy động cơ tiếp tục với u. Và usẽ phù hợp với u . Vì vậy, nỗ lực đối sánh này đã thành công. qu là phù hợp

Hãy áp dụng q(?!i)uđể bỏ . Ngay cả trong trường hợp này, lookahead là tích cực (vì ikhông khớp) và được theo sau bởi một mã thông báo khác. Một lần nữa, qkhớp với qikhông khớp với u . Kết quả phù hợp từ lookahead phải bị loại bỏ, do đó, động cơ lùi từ utrong chuỗi sang u . Nhìn trước đã thành công, vì vậy động cơ tiếp tục với u. Và usẽ phù hợp với u . Vì vậy, nỗ lực đối sánh này đã thành công. qu là phù hợp

Vì vậy, kết luận lại, sự khác biệt thực sự giữa nhóm nhìn trước và nhóm không chụp là tất cả nếu bạn muốn chỉ kiểm tra sự tồn tại hoặc kiểm tra và lưu kết quả phù hợp. Chụp nhóm rất tốn kém vì vậy hãy sử dụng nó một cách thận trọng.


> do đó động cơ lùi từ i trong chuỗi sang u. Nhìn trước đã thành công, vì vậy động cơ tiếp tục với i. Nhưng tôi không thể phù hợp với bạn. Điều này hoàn toàn khó hiểu. Tại sao bước trở lại nếu điều này được lookahead ?
Green

1
@Green Một điều quan trọng cần hiểu về lookahead và các cấu trúc lookaround khác là mặc dù chúng xem xét các chuyển động để xem liệu biểu thức con của chúng có thể khớp hay không, chúng thực sự không “sử dụng” bất kỳ văn bản nào. Điều đó có thể hơi khó hiểu
freedev Ngày

7

Thử kết hợp foobarvới những điều này:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

Regex đầu tiên sẽ khớp và sẽ trả về "bar" dưới dạng submatch đầu tiên - (?=b)khớp với 'b', nhưng không sử dụng nó, để nó trong dấu ngoặc đơn sau.

Regex thứ hai sẽ KHÔNG khớp, bởi vì nó mong đợi "foo" được theo sau bởi một cái gì đó khác với 'b'.

(?:...)có tác dụng chính xác như simple (...), nhưng nó không trả về phần đó dưới dạng một submatch.


0

Cách đơn giản nhất để hiểu các xác nhận là coi chúng như lệnh được chèn vào một biểu thức chính quy. Khi động cơ chạy đến một xác nhận, nó sẽ ngay lập tức kiểm tra tình trạng được mô tả bởi khẳng định. Nếu kết quả là true, thì hãy tiếp tục chạy biểu thức chính quy.


0

Đây là sự khác biệt thực sự:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

Nếu bạn không quan tâm đến nội dung sau "?:" Hoặc "? =", "?:" Và "? =" Giống nhau. Cả hai đều sử dụng được.

Nhưng nếu bạn cần những nội dung đó cho quá trình tiếp theo (không chỉ khớp toàn bộ. Trong trường hợp đó, bạn có thể chỉ cần sử dụng "a (b)"), bạn phải sử dụng "? =" Để thay thế. Nguyên nhân "?:" sẽ thông qua nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.