Biểu thức chính quy để có được một chuỗi giữa hai chuỗi trong JavaScript
Giải pháp đầy đủ nhất sẽ hoạt động trong phần lớn các trường hợp là sử dụng một nhóm chụp với mô hình khớp dấu chấm lười biếng . Tuy nhiên, một dấu chấm .
trong regex JavaScript không khớp với các ký tự ngắt dòng, vì vậy, những gì sẽ hoạt động trong 100% trường hợp là [^]
hoặc [\s\S]
/ [\d\D]
/ [\w\W]
cấu trúc.
ECMAScript 2018 và giải pháp tương thích mới hơn
Trong các môi trường JavaScript hỗ trợ ECMAScript 2018 , công cụ s
sửa đổi cho phép .
khớp bất kỳ char nào kể cả ký tự ngắt dòng và công cụ regex hỗ trợ các giao diện có độ dài thay đổi. Vì vậy, bạn có thể sử dụng regex như
var result = s.match(/(?<=cow\s+).*?(?=\s+milk)/gs); // Returns multiple matches if any
// Or
var result = s.match(/(?<=cow\s*).*?(?=\s*milk)/gs); // Same but whitespaces are optional
Trong cả hai trường hợp, vị trí hiện tại được kiểm tra cow
với bất kỳ khoảng trắng 1/0 nào trở lên sau cow
đó, sau đó mọi ký tự 0+ càng ít càng tốt sẽ được khớp và tiêu thụ (= thêm vào giá trị khớp), và sau đómilk
được kiểm tra (với bất kỳ 1/0 hoặc nhiều khoảng trắng trước chuỗi con này).
Kịch bản 1: Đầu vào một dòng
Điều này và tất cả các kịch bản khác dưới đây được hỗ trợ bởi tất cả các môi trường JavaScript. Xem ví dụ sử dụng ở dưới cùng của câu trả lời.
cow (.*?) milk
cow
được tìm thấy đầu tiên, sau đó là khoảng trắng, sau đó bất kỳ ký tự 0+ nào khác ngoài ký tự ngắt dòng, càng ít càng tốt, *?
là một bộ định lượng lười biếng, được ghi vào Nhóm 1 và sau đó một khoảng trắng milk
phải tuân theo (và chúng được khớp và tiêu thụ , quá ).
Kịch bản 2: Đầu vào đa dòng
cow ([\s\S]*?) milk
Ở đây cow
và một khoảng trắng được khớp trước, sau đó bất kỳ ký tự 0+ nào càng ít càng tốt sẽ được khớp và được ghi vào Nhóm 1, và sau đó là khoảng trắng cómilk
được khớp.
Kịch bản 3: Các trận đấu chồng chéo
Nếu bạn có một chuỗi thích >>>15 text>>>67 text2>>>
và bạn cần có 2 trận đấu ở giữa >>>
+ number
+ whitespace
và >>>
, bạn không thể sử dụng />>>\d+\s(.*?)>>>/g
vì điều này sẽ chỉ tìm thấy 1 trận đấu do thực tế >>>
trước đó 67
đã được sử dụng khi tìm trận đấu đầu tiên. Bạn có thể sử dụng giao diện tích cực để kiểm tra sự hiện diện của văn bản mà không thực sự "ngấu nghiến" nó (tức là nối thêm vào trận đấu):
/>>>\d+\s(.*?)(?=>>>)/g
Xem bản demo regex trực tuyến mang lại text1
vàtext2
như nội dung của Nhóm 1 được tìm thấy.
Ngoài ra, hãy xem Làm thế nào để có được tất cả các kết quả trùng lặp có thể có cho một chuỗi .
Cân nhắc hiệu suất
Mẫu kết hợp dấu chấm lười biếng ( .*?
) bên trong các mẫu biểu thức chính quy có thể làm chậm quá trình thực thi tập lệnh nếu đầu vào rất dài được đưa ra. Trong nhiều trường hợp, kỹ thuật unroll-the-loop giúp ở mức độ lớn hơn. Cố gắng lấy tất cả từ giữa cow
và milk
từ "Their\ncow\ngives\nmore\nmilk"
, chúng tôi thấy rằng chúng tôi chỉ cần khớp tất cả các dòng không bắt đầu milk
, do đó, thay vì cow\n([\s\S]*?)\nmilk
chúng tôi có thể sử dụng:
/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm
Xem bản demo regex (nếu có thể \r\n
, sử dụng /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm
). Với chuỗi thử nghiệm nhỏ này, hiệu suất đạt được là không đáng kể, nhưng với văn bản rất lớn, bạn sẽ cảm thấy sự khác biệt (đặc biệt là nếu các dòng dài và ngắt dòng không nhiều lắm).
Mẫu sử dụng regex trong JavaScript:
//Single/First match expected: use no global modifier and access match[1]
console.log("My cow always gives milk".match(/cow (.*?) milk/)[1]);
// Multiple matches: get multiple matches with a global modifier and
// trim the results if length of leading/trailing delimiters is known
var s = "My cow always gives milk, thier cow also gives milk";
console.log(s.match(/cow (.*?) milk/g).map(function(x) {return x.substr(4,x.length-9);}));
//or use RegExp#exec inside a loop to collect all the Group 1 contents
var result = [], m, rx = /cow (.*?) milk/g;
while ((m=rx.exec(s)) !== null) {
result.push(m[1]);
}
console.log(result);
Sử dụng String#matchAll
phương pháp hiện đại
const s = "My cow always gives milk, thier cow also gives milk";
const matches = s.matchAll(/cow (.*?) milk/g);
console.log(Array.from(matches, x => x[1]));