2013-06-10 57 views
6

Trong javascript, tôi có một chuỗi abcdef và không thể tìm ra hành vi kỳ lạ này:Tại sao "abcdef" không khớp với (? = Abc) def nhưng được so khớp bởi abc (? = Def)?

  • (?=abc)def doesnt phù hợp với chuỗi
  • abc(?=def) không phù hợp với chuỗi

Tại sao?

+0

Có thể bạn muốn '(?: Abc) def' thay thế, sử dụng nhóm không bắt thay vì nhìn tích cực. – DaoWen

+0

@ DaoWen Không, tôi đã thử rằng ... thử '" abcdef ".replace (/ (?: abc) def /," ")' nó thay thế toàn bộ chuỗi – Zaffy

Trả lời

18

Trong (?=abc)def chụp (?=abc) không có chiều rộng bằng 0 và không di chuyển con trỏ tiến lên trong chuỗi đầu vào sau một kết quả thành công. Cấu trúc đó chỉ đơn giản là nói về phía trước ở ba ký tự tiếp theo để xem chúng có phải là abc hay không, nếu sau đó chúng kiểm tra xem các ký tự đó có là def hay không. Tại thời điểm này, trận đấu không thành công ..

Bạn cần hiểu cách thức hoạt động của công cụ regex để hoàn thành trận đấu của mình. Xem xét chuỗi đầu vào của bạn abcdef và regex abc(?=def) của bạn. Động cơ bắt đầu bằng cách kết hợp a rồi di chuyển con trỏ bên trong chuỗi đầu vào sang ký tự tiếp theo và cố gắng khớp với b vì con trỏ trong chuỗi đầu vào nằm trên b kết quả thành công. Sau đó, công cụ sẽ di chuyển con trỏ bên trong chuỗi đầu vào và cố gắng khớp với c và bởi vì con trỏ nằm trong chuỗi đầu vào là trên c kết quả thành công và con trỏ trong chuỗi đầu vào được di chuyển sang ký tự tiếp theo. Bây giờ động cơ gặp (?=def) tại thời điểm này động cơ chỉ nhìn về phía trước để xem liệu ba ký tự tiếp theo từ nơi con trỏ nằm trong sting đầu vào có thực tế là def mà không di chuyển con trỏ hay không.

Bây giờ hãy xem chuỗi đầu vào xyz và regex x(?=y)Z. Công cụ regex đặt con trỏ trên chữ cái đầu tiên trong chuỗi đầu vào và kiểm tra xem nó có phải là x và thấy rằng x để nó di chuyển con trỏ đến ký tự tiếp theo trong chuỗi đầu vào. Bây giờ nó trông phía trước để xem nếu nhân vật tiếp theo là một y, mà nó được, nhưng động cơ không di chuyển đầu vào con trỏ văn bản đầu vào để con trỏ trong văn bản đầu vào nằm trên y. Tiếp theo, động cơ sẽ kiểm tra xem con trỏ có nằm trên ký tự z hay không, nhưng vì con trỏ trong văn bản đầu vào vẫn nằm trên chữ cái y, kết quả không thành công.

Bạn có thể đọc nhiều hơn về lookaheads cả tích cực và tiêu cực tại http://www.regular-expressions.info/lookaround.html

+0

Vẫn chưa có nó. Nếu nó phải là "sau" một cái gì đó cố gắng để thêm '^' lúc đầu, kết quả sẽ giống nhau. – Zaffy

+1

Đã cập nhật giải thích để đề cập đến cách thức công cụ regex xử lý kết quả phù hợp thành công và hiển thị điều gì sẽ xảy ra nếu lookahead được chèn vào giữa biểu thức mẫu. Điều quan trọng là theo dõi nơi con trỏ ở bên trong văn bản đầu vào. –

+1

giải thích tuyệt vời! – user1993

2

MDN definition of lookaheads trong javascript 'x'

x(?=y)
Matches chỉ khi 'x' Tiếp theo là 'y'. Điều này được gọi là một lookahead.

Ví dụ: /Jack(?=Sprat)/ chỉ khớp với 'Jack' nếu tiếp theo là 'Sprat'. /Jack(?=Sprat|Frost)/ chỉ khớp với 'Jack' nếu nó được theo sau bởi 'Sprat' hoặc 'Frost'. Tuy nhiên, không phải 'Sprat' hay 'Frost' là một phần của kết quả trận đấu.

Vì vậy, (?=y) được đặt trước bằng một tuyên bố khác, trong trường hợp này là một chuỗi trống, sau đó nó sẽ chỉ khớp với câu lệnh đầu tiên sau câu thứ hai.Nếu không có tuyên bố hàng đầu, biểu thức (?="abc") sẽ khớp với 3 ký tự đầu tiên abc mà không cần chụp chúng và sau đó kiểm tra lại để xem các ký tự đó có bị lỗi hay không, điều này sẽ thất bại.

4

(?=...) là một cách nhìn khác, nói cách khác là kiểm tra chuỗi ở bên phải. Lưu ý rằng một lookahead là một xác nhận chiều rộng bằng 0 mà không ăn ký tự. Trong ví dụ đầu tiên của bạn: (?=abc) có nghĩa là phải được theo sau bởi abc cuộc gặp gỡ def. Đây là lý do tại sao mẫu bị lỗi.

Trong bạn ví dụ thứ hai mà nó tìm thấy def sau abc, sau đó chuỗi là lần xuất hiện

+1

Rất rõ ràng giải thích về xác nhận chiều rộng bằng không, nó cũng giải thích tại sao '/ (? = Def) def/.test ('abcdef')' phù hợp. –

2

Dựa tắt trả lời của bạn để nhận xét của tôi, tôi nghĩ rằng những gì bạn muốn là một positive look-behind:

(?<=abc)def 

Sửa :

Vì bạn đang sử dụng JavaScript (xin lỗi, tôi chỉ đọc câu hỏi của bạn — tôi didn ' t nhìn vào các thẻ), tại sao không chỉ sử dụng một nhóm chụp thường xuyên và bao gồm các trận đấu trong mô hình thay thế?

"abcdef".replace(/(abc)def/, "$1") 
+0

Chắc chắn, điều này sẽ là * cổ điển * nhưng trong javascript không có lookbehinds. – Zaffy

+0

Bởi vì khi thay thế bằng '/ g', nó sẽ bỏ qua văn bản được thay thế. Ví dụ: "a1a2a" .replace (/ (a) (\ d) (a)/g, "$ 1b $ 2b $ 3"); 'sẽ là' ab1ba2a' không phải 'ab1bab2ba' – Zaffy

+0

@Zaffy - Chỉ thay thế giao diện - * đằng sau * với các nhóm chụp, không nhìn - * phía trước *, ví dụ: "" a1a2a ".replace (/ (a) (\ d) (? = a)/g," $ 1b $ 2b ") // = > "ab1bab2ba" – DaoWen

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