regex javascript - nhìn phía sau thay thế?


142

Đây là một regex hoạt động tốt trong hầu hết các triển khai regex:

(?<!filename)\.js$

Điều này khớp với .js cho một chuỗi kết thúc bằng .js ngoại trừ filename.js

Javascript không có giao diện regex. Có ai có thể kết hợp một biểu thức chính thay thế để đạt được kết quả tương tự và hoạt động trong javascript không?

Dưới đây là một số suy nghĩ, nhưng cần chức năng trợ giúp. Tôi đã hy vọng đạt được nó chỉ với một regex: http://blog.stevenlevithan.com/archives/mimic-lookbehind-javascript


3
Nếu bạn chỉ cần kiểm tra một tên tệp cụ thể hoặc danh sách tên tệp, tại sao không sử dụng hai kiểm tra? kiểm tra xem nó kết thúc bằng .js và sau đó nếu có, kiểm tra xem nó không khớp với filename.js hoặc ngược lại.
si28719e

3
Cập nhật: Phiên bản Chrome công khai mới nhất (v62) bao gồm các giao diện (có lẽ là thử nghiệm) ra khỏi hộp: D Lưu ý tuy nhiên các lookbehind vẫn đang trong giai đoạn đề xuất 3: github.com/tc39/proposed-regapid-lookbehind . Vì vậy, có thể mất một lúc cho đến khi JavaScript ở mọi nơi hỗ trợ nó. Tốt hơn hãy cẩn thận về việc sử dụng trong sản xuất!
Eirik Birkeland

2
# Cập nhật: ES2018 bao gồm các xác nhận lookbehind Plus : - chế độ dot ALL (cờ s) - Xác nhận Lookbehind - Các nhóm bắt giữ được đặt tên - Thoát tài sản Unicode
Ashley Coolman

2
Chỉ sử dụng (?<=thingy)thingycho cái nhìn tích cực(?<!thingy)thingycho cái nhìn tiêu cực . Bây giờ nó hỗ trợ họ.
Toàn cảnh

7
@ K._ Kể từ tháng 2 năm 2018 điều đó vẫn chưa đúng !! Và nó sẽ cần một chút thời gian vì các trình duyệt và công cụ phải thực hiện các đặc tả (hiện tại trong bản nháp).
Andre Figueiredo

Câu trả lời:


64

^(?!filename).+\.js làm việc cho tôi

thử nghiệm chống lại:

  • phù hợp với test.js
  • trận đấu blabla.js
  • filename.js không khớp

Có thể tìm thấy lời giải thích phù hợp cho biểu thức chính quy này tại Biểu thức chính quy để khớp chuỗi không chứa từ?

Nhìn về phía trước là có sẵn kể từ phiên bản 1.5 của javascript và được hỗ trợ bởi tất cả các trình duyệt chính

Đã cập nhật để khớp với filename2.js và 2filename.js nhưng không phải là filename.js

(^(?!filename\.js$).).+\.js


5
Câu hỏi mà bạn đã liên kết để nói về một vấn đề hơi khác: khớp một chuỗi không chứa từ mục tiêu ở bất cứ đâu . Chuỗi này đơn giản hơn nhiều: khớp với một chuỗi không bắt đầu bằng từ đích.
Alan Moore

Đó thực sự là tốt đẹp, nó chỉ bỏ lỡ trong các trường hợp như: filename2.js hoặc filenameddk.js hoặc tương tự. Đây là một trận đấu không có, nhưng nên là một trận đấu.
daniel

9
@daniel Bạn yêu cầu nhìn phía sau, không phải nhìn về phía trước, tại sao bạn lại chấp nhận câu trả lời này?
hek2mgl

1
cái đã cho không khớp vớia.js
inetph Phantom 17/03/2016

1
Regex ban đầu với lookbehind không khớp 2filename.js, nhưng regex được đưa ra ở đây thì có. Một cái thích hợp hơn sẽ là ^(?!.*filename\.js$).*\.js$. Điều này có nghĩa, phù hợp với bất kỳ *.js ngoại trừ *filename.js .
weibeld

152

EDIT: Từ ECMAScript 2018 trở đi, các xác nhận của lookbehind (thậm chí không bị ràng buộc) được hỗ trợ nguyên bản .

Trong các phiên bản trước, bạn có thể làm điều này:

^(?:(?!filename\.js$).)*\.js$

Điều này không rõ ràng những gì biểu thức lookbehind đang làm ngầm: kiểm tra từng ký tự của chuỗi nếu biểu thức lookbehind cộng với regex sau khi nó không khớp và chỉ sau đó cho phép ký tự đó khớp.

^                 # Start of string
(?:               # Try to match the following:
 (?!              # First assert that we can't match the following:
  filename\.js    # filename.js 
  $               # and end-of-string
 )                # End of negative lookahead
 .                # Match any character
)*                # Repeat as needed
\.js              # Match .js
$                 # End of string

Chỉnh sửa khác:

Tôi đau đớn nói (đặc biệt là vì câu trả lời này đã được nêu lên rất nhiều) rằng có một cách dễ dàng hơn nhiều để thực hiện mục tiêu này. Không cần phải kiểm tra giao diện ở mỗi nhân vật:

^(?!.*filename\.js$).*\.js$

cũng hoạt động tốt:

^                 # Start of string
(?!               # Assert that we can't match the following:
 .*               # any string, 
  filename\.js    # followed by filename.js
  $               # and end-of-string
)                 # End of negative lookahead
.*                # Match any string
\.js              # Match .js
$                 # End of string

Hoạt động trên nhiều trường hợp trừ trường hợp có các ký tự có sẵn, ví dụ: filename.js (works-nomatch) filename2.js (work-match) blah.js (hoạt động - khớp) 2filename.js (không hoạt động - nomatch) --- đã nói rằng, cái nhìn có cùng giới hạn mà tôi không nhận ra cho đến bây giờ ...
daniel

9
@daniel: Chà, regex của bạn (với lookbehind) cũng không khớp 2filename.js. Regex của tôi khớp chính xác trong các trường hợp giống như regex ví dụ của bạn.
Tim Pietzcker

Tha thứ cho sự ngây thơ của tôi nhưng có sử dụng cho nhóm không bắt giữ ở đây không? Tôi luôn biết rằng chỉ hữu ích khi cố gắng thu thập lại tài liệu tham khảo để thay thế trong một chuỗi. Theo như tôi biết, điều này cũng sẽ hoạt động ^ (?! Tên tệp \ .js $). * \. Js $
Tôi muốn trả lời

1
Không hoàn toàn, regex đó chỉ kiểm tra "filename.js" khi bắt đầu chuỗi. Nhưng ^(?!.*filename\.js$).*\.js$sẽ làm việc. Cố gắng nghĩ về những tình huống mà nhóm nc vẫn có thể cần thiết ...
Tim Pietzcker

Cách tiếp cận này có thể được tóm tắt là: thay vì nhìn phía sau X, hãy nhìn về phía trước mọi nhân vật xuất hiện trước X?
Sarsaparilla

25

Giả sử bạn muốn tìm tất cả intkhông có trước unsigned:

Với sự hỗ trợ cho cái nhìn tiêu cực phía sau:

(?<!unsigned )int

Không hỗ trợ cho cái nhìn tiêu cực phía sau:

((?!unsigned ).{9}|^.{0,8})int

Về cơ bản, ý tưởng là lấy n ký tự trước và loại trừ khớp với nhìn phía trước tiêu cực, nhưng cũng khớp với các trường hợp không có n ký tự đi trước. (trong đó n là chiều dài của nhìn phía sau).

Vì vậy, regex trong câu hỏi:

(?<!filename)\.js$

sẽ dịch sang:

((?!filename).{8}|^.{0,7})\.js$

Bạn có thể cần chơi với các nhóm bắt để tìm vị trí chính xác của chuỗi mà bạn quan tâm hoặc bạn không muốn thay thế phần cụ thể bằng thứ khác.


Tôi chỉ chuyển đổi này: (?<!barna)(?<!ene)(?<!en)(?<!erne) (?:sin|vår)e?(?:$| (?!egen|egne))để (?!barna).(?!erne).(?!ene).(?!en).. (?:sin|vår)e?(?:$| (?!egen|egne))mà hiện các trick cho nhu cầu của tôi. Chỉ cung cấp điều này như một kịch bản "thế giới thực" khác. Xem liên kết
Eirik Birkeland

Tôi nghĩ bạn có nghĩa là:((?!unsigned ).{9}|^.{0,8})int
pansay

@pansay Vâng. Cảm ơn bạn. Tôi chỉ sửa chữa phản ứng của tôi.
Kamil Szot

2
Cảm ơn câu trả lời khái quát hơn, hoạt động ngay cả khi có nhu cầu khớp sâu trong văn bản (nơi ban đầu ^ sẽ không thực tế)!
Milos Mrdovic

5

Nếu bạn có thể nhìn về phía trước nhưng quay lại, bạn có thể đảo ngược chuỗi trước và sau đó thực hiện một cái nhìn. Một số công việc nữa sẽ cần phải được thực hiện, tất nhiên.


8
Câu trả lời này thực sự có thể sử dụng một số cải tiến. Nó có vẻ giống như một bình luận cho tôi.
mickmackusa

2

Đây là một giải pháp tương đương với câu trả lời của Tim Pietzcker (xem thêm bình luận của cùng một câu trả lời):

^(?!.*filename\.js$).*\.js$

Nó có nghĩa, phù hợp *.jsngoại trừ *filename.js.

Để có được giải pháp này, bạn có thể kiểm tra các mẫu mà giao diện phủ định loại trừ, và sau đó loại trừ chính xác các mẫu này với giao diện phủ định.


-1

Dưới đây là một thay thế JavaScript nhìn tích cực cho thấy cách lấy tên cuối cùng của những người có 'Michael' làm tên đầu tiên của họ.

1) Cho văn bản này:

const exampleText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";

có được một loạt tên cuối cùng của những người tên Michael. Kết quả sẽ là:["Jordan","Johnson","Green","Wood"]

2) Giải pháp:

function getMichaelLastName2(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(person.indexOf(' ')+1));
}

// or even
    .map(person => person.slice(8)); // since we know the length of "Michael "

3) Kiểm tra giải pháp

console.log(JSON.stringify(    getMichaelLastName(exampleText)    ));
// ["Jordan","Johnson","Green","Wood"]

Demo tại đây: http://codepen.io/PiotrBerebecki/pen/GjwRoo

Bạn cũng có thể dùng thử bằng cách chạy đoạn trích bên dưới.

const inputText = "Michael, how are you? - Cool, how is John Williamns and Michael Jordan? I don't know but Michael Johnson is fine. Michael do you still score points with LeBron James, Michael Green Miller and Michael Wood?";



function getMichaelLastName(text) {
  return text
    .match(/(?:Michael )([A-Z][a-z]+)/g)
    .map(person => person.slice(8));
}

console.log(JSON.stringify(    getMichaelLastName(inputText)    ));

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.