Biểu thức chính quy để có được một chuỗi giữa hai chuỗi trong Javascript


166

Tôi đã tìm thấy những bài viết rất giống nhau, nhưng tôi hoàn toàn không thể có được biểu hiện thường xuyên của mình ngay tại đây.

Tôi đang cố gắng viết một biểu thức chính quy trả về một chuỗi nằm giữa hai chuỗi khác. Ví dụ: Tôi muốn lấy chuỗi nằm giữa chuỗi "bò" và "sữa".

Con bò của tôi luôn cho sữa

sẽ trở lại

"luôn luôn cho"

Đây là biểu thức tôi đã chắp ghép cho đến nay:

(?=cow).*(?=milk)

Tuy nhiên, điều này trả về chuỗi "bò luôn cho".


6
Tôi vấp phải câu hỏi cũ này và muốn làm rõ tại sao testRE là một mảng. test.match trả về một mảng có chỉ mục đầu tiên là tổng số khớp (do đó, chuỗi khớp với sữa bò (. *)) và sau đó, tất cả các chuỗi bị mắc kẹt như (. *) nếu có một dấu ngoặc đơn thứ hai chúng sẽ sau đó ở trong testRE [2]
Salketer

4
Giải pháp này sẽ không hoạt động nếu bạn đang tìm kiếm một chuỗi chứa dòng mới. Trong trường hợp như vậy, bạn nên sử dụng "STRING_ONE ([\\ s \\ S] *?) STRING_TWO". stackoverflow.com/questions/22531252/
Mạnh

chỉ để tham khảo phương thức đối sánh trên MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/
Kẻ

Câu trả lời:


183

Một cái nhìn ( (?=phần đó ) không tiêu thụ bất kỳ đầu vào. Đó là một xác nhận có độ rộng bằng không (cũng như kiểm tra ranh giới và giao diện).

Bạn muốn một trận đấu thường xuyên ở đây, để tiêu thụ cowphần. Để chụp phần ở giữa, bạn sử dụng nhóm chụp (chỉ cần đặt phần mẫu bạn muốn chụp trong ngoặc đơn):

cow(.*)milk

Không có cái nhìn nào là cần thiết cả.


26
Khi tôi kiểm tra điều này, biểu thức Regex được cung cấp bao gồm cả "bò" và "sữa" ...
TheCascadian

4
Đây là một bước thiếu. Khi bạn nhận được kết quả của trận đấu, bạn cần trích xuất văn bản phù hợp của nhóm chụp đầu tiên matched[1], chứ không phải toàn bộ văn bản khớp với matched[0].
Rory O'Kane

7
Trong Javascript, bạn thực sự cần phải sử dụng ([\s\S]*?)chứ không phải (.*?).
Qian Chen

7
Mặc dù đây là một kỹ thuật hữu ích, nhưng nó đã bị đánh giá thấp bởi vì IMHO đây không phải là câu trả lời đúng cho câu hỏi, vì nó bao gồm "bò" và "sữa", như tuyên bố của @TheCascadian
Almir Campos

@AlmirCampos - nếu tôi không nhầm thì không có cách nào để thực hiện trận đấu này mà không khớp "bò" và "sữa" (vì bạn muốn ghép những gì ở giữa hai thứ đó). Vấn đề không nằm ở chính RegEx mà là cách bạn xử lý nó sau đó (như được đề cập bởi Rory O'Kane). Nếu không, bạn chỉ có thể phù hợp với các không gian xung quanh - và điều đó sẽ mang lại cho bạn sự trở lại RẤT sai, phải không?
sinh

69

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ụ ssử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 cowvớ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 milkphả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 cowvà 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>>>, bạn không thể sử dụng />>>\d+\s(.*?)>>>/gvì đ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 text1text2 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 cowmilktừ "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]*?)\nmilkchú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#matchAllphươ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]));


51

Đây là một regex sẽ lấy những gì giữa bò và sữa (không có khoảng trống dẫn đầu / dấu vết):

srctext = "My cow always gives milk.";
var re = /(.*cow\s+)(.*)(\s+milk.*)/;
var newtext = srctext.replace(re, "$2");

Một ví dụ: http://jsfiddle.net/entropo/tkP74/


17
  • Bạn cần nắm bắt .*
  • Bạn có thể (nhưng không phải) làm cho sự .*hư vô
  • Thực sự không cần thiết cho cái nhìn.

    > /cow(.*?)milk/i.exec('My cow always gives milk');
    ["cow always gives milk", " always gives "]

Trong trường hợp cụ thể này, nếu nó tham lam, nó sẽ đi đến cuối và quay lại (có lẽ).
Ben

9

Câu trả lời được chọn không có tác dụng với tôi ... hmm ...

Chỉ cần thêm không gian sau bò và / hoặc trước sữa để cắt khoảng trống từ "luôn luôn cho"

/(?<=cow ).*(?= milk)/

nhập mô tả hình ảnh ở đây


Bạn không cần bình luận về câu trả lời của riêng bạn, chỉ cần chỉnh sửa nó.
Cody

Nhìn phía sau ?<=không được hỗ trợ trong Javascript.
Mark Carpenter Jr

@MarkCarpenterJr nếu bạn đã kiểm tra nó qua regextester.com , bạn sẽ nhận được gợi ý đó. Có vẻ như trang web đã dựa trên các quy tắc của nó từ đặc điểm kỹ thuật cũ hơn. Lookbehind hiện được hỗ trợ. Xem stackoverflow.com/questions/30118815/ ( Và mẫu hoạt động tốt với các trình duyệt hiện đại không có lỗi. Hãy thử kiểm tra này thay vì regex101.com
duduwe

@ CodyG.ah vâng. hiểu rồi.
duduwe

8

Tôi đã có thể có được những gì tôi cần bằng cách sử dụng giải pháp của Martinho Fernandes bên dưới. Mã này là:

var test = "My cow always gives milk";

var testRE = test.match("cow(.*)milk");
alert(testRE[1]);

Bạn sẽ nhận thấy rằng tôi đang cảnh báo biến testRE dưới dạng một mảng. Điều này là do testRE đang trở lại dưới dạng một mảng, vì một số lý do. Đầu ra từ:

My cow always gives milk

Thay đổi thành:

always gives

1
Cảm ơn, tôi đã thêm một fiddle ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) cho nó. / Johan
Mosca Pt

4

Chỉ cần sử dụng biểu thức chính quy sau:

(?<=My cow\s).*?(?=\smilk)

Nhìn phía sau ?<=không được hỗ trợ trong Javascript. Sẽ là cách để làm điều đó mặc dù.
Mark Carpenter Jr

Nó được hỗ trợ trong JavaScript. Nó không được hỗ trợ trong Safari và Mozilla (chưa), chỉ trong Chrome và Opera.
Paul Strupeikis

3

Tôi thấy regex là tẻ nhạt và tốn thời gian cho cú pháp. Vì bạn đã sử dụng javascript, nên làm như sau sẽ dễ dàng hơn nếu không có regex:

const text = 'My cow always gives milk'
const start = `cow`;
const end = `milk`;
const middleText = text.split(start)[1].split(end)[0]
console.log(middleText) // prints "always gives"

2
Làm việc cho tôi! câu trả lời tuyệt vời bởi vì nó thực sự đơn giản! :)
Andrew Irwin

2

Nếu dữ liệu nằm trên nhiều dòng thì bạn có thể phải sử dụng như sau,

/My cow ([\s\S]*)milk/gm

My cow always gives 
milk

Ví dụ 101


0

Phương thức match () tìm kiếm một chuỗi cho khớp và trả về một đối tượng Array.

// Original string
var str = "My cow always gives milk";

// Using index [0] would return<br/>
// "**cow always gives milk**"
str.match(/cow(.*)milk/)**[0]**


// Using index **[1]** would return
// "**always gives**"
str.match(/cow(.*)milk/)[1]

0

Bài tập

Trích xuất chuỗi con giữa hai chuỗi (không bao gồm hai chuỗi này)

Giải pháp

let allText = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum";
let textBefore = "five centuries,";
let textAfter = "electronic typesetting";
var regExp = new RegExp(`(?<=${textBefore}\\s)(.+?)(?=\\s+${textAfter})`, "g");
var results = regExp.exec(allText);
if (results && results.length > 1) {
    console.log(results[0]);
}
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.