Ekspresi reguler untuk mendapatkan string antara dua string dalam Javascript


166

Saya telah menemukan posting yang sangat mirip, tetapi saya tidak bisa mendapatkan ekspresi reguler saya di sini.

Saya mencoba untuk menulis ekspresi reguler yang mengembalikan string yang berada di antara dua string lainnya. Sebagai contoh: Saya ingin mendapatkan string yang berada di antara string "sapi" dan "susu".

Sapi saya selalu memberi susu

akan kembali

"selalu memberi"

Inilah ungkapan yang telah saya kumpulkan bersama sejauh ini:

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

Namun, ini mengembalikan string "sapi selalu memberi".


6
Saya menemukan pertanyaan lama ini dan ingin menjelaskan mengapa testRE adalah sebuah array. test.match mengembalikan array dengan indeks pertama sebagai total kecocokan (untuk itu, string yang cocok dengan susu sapi (. *)) dan kemudian, semua string yang terperangkap seperti (. *) jika ada set kurung kedua yang mereka inginkan kemudian di testRE [2]
Salketer

4
Solusi ini tidak akan berfungsi jika Anda mencari string yang berisi baris baru. Dalam kasus seperti itu, Anda harus menggunakan "STRING_ONE ([\\ s \\ S] *?) STRING_TWO". stackoverflow.com/questions/22531252/…
Michael.Lumley

hanya untuk referensi metode pertandingan di MDN developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
vzR

Jawaban:


183

Seorang lookahead ( (?=bagian itu) tidak mengkonsumsi input apa pun. Ini adalah pernyataan nol-lebar (seperti halnya pemeriksaan batas dan lihat di belakang).

Anda ingin pasangan reguler di sini, untuk mengkonsumsi cowporsinya. Untuk menangkap bagian di antaranya, Anda menggunakan grup penangkap (cukup masukkan bagian pola yang ingin Anda tangkap di dalam tanda kurung):

cow(.*)milk

Tidak ada lookaheads yang diperlukan sama sekali.


26
Saat saya mengujinya, ekspresi Regex yang disediakan mencakup "sapi" dan "susu" ...
TheCascadian

4
Ini tidak ada langkah. Saat Anda mendapatkan hasil pertandingan, Anda perlu mengekstraksi teks yang cocok dengan grup penangkap pertama matched[1], bukan keseluruhan teks yang cocok dengan matched[0].
Rory O'Kane

7
Dalam Javascript, Anda sebenarnya harus menggunakan ([\s\S]*?)daripada (.*?).
Qian Chen

7
Meskipun ini adalah teknik yang berguna, itu dibatalkan karena IMHO ini BUKAN jawaban yang tepat untuk pertanyaan, karena itu termasuk "sapi" dan "susu", sebagaimana dinyatakan oleh @TheCascadian
Almir Campos

@AlmirCampos - jika saya tidak salah, tidak ada cara untuk melakukan pertandingan ini tanpa mencocokkan "sapi" dan "susu" (karena Anda ingin mencocokkan apa yang ada di antara keduanya). Masalahnya bukan pada RegEx itu sendiri tetapi bagaimana Anda menanganinya setelah itu (seperti yang disebutkan oleh Rory O'Kane). Kalau tidak, Anda hanya bisa cocok dengan ruang sekitarnya - dan itu akan memberi Anda pengembalian yang SANGAT salah, bukan?
lahir

69

Ekspresi reguler untuk mendapatkan string antara dua string dalam JavaScript

Solusi paling lengkap yang akan bekerja di sebagian besar kasus adalah menggunakan grup penangkap dengan pola pencocokan titik malas . Namun, sebuah titik .dalam regex JavaScript tidak cocok dengan karakter pemisah baris, jadi, apa yang akan berfungsi dalam 100% kasus adalah konstruksi [^]atau [\s\S]/ [\d\D]/ [\w\W].

ECMAScript 2018 dan solusi kompatibel yang lebih baru

Dalam lingkungan JavaScript yang mendukung ECMAScript 2018 , spengubah memungkinkan .untuk mencocokkan karakter apa pun termasuk karakter line break, dan mesin regex mendukung tampilan di balik panjang variabel. Jadi, Anda bisa menggunakan regex like

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

Dalam kedua kasus, posisi saat ini diperiksa cowdengan spasi putih 1/0 atau lebih setelahnya cow, maka 0+ karakter sesedikit mungkin dicocokkan dan dikonsumsi (= ditambahkan ke nilai pertandingan), dan kemudian milkdiperiksa untuk (dengan 1/0 atau lebih spasi putih sebelum substring ini).

Skenario 1: Input satu baris

Ini dan semua skenario lainnya di bawah ini didukung oleh semua lingkungan JavaScript. Lihat contoh penggunaan di bagian bawah jawaban.

cow (.*?) milk

cowditemukan pertama, lalu spasi, lalu 0+ karakter apa pun selain karakter baris, sesedikit mungkin *?kuantifier malas, dimasukkan ke Grup 1 dan kemudian spasi dengan milkharus mengikuti (dan yang dicocokkan dan dikonsumsi , juga ).

Skenario 2: Input multiline

cow ([\s\S]*?) milk

Di sini, cowdan spasi dicocokkan terlebih dahulu, maka 0+ karakter apa pun yang sesedikit mungkin dicocokkan dan ditangkap ke dalam Grup 1, dan kemudian spasi dengan milkdicocokkan.

Skenario 3: Pertandingan yang tumpang tindih

Jika Anda memiliki string seperti >>>15 text>>>67 text2>>>dan Anda perlu mendapatkan 2 kecocokan di antara >>>+ number+ whitespacedan >>>, Anda tidak dapat menggunakan />>>\d+\s(.*?)>>>/gkarena ini hanya akan menemukan 1 kecocokan karena fakta >>>sebelumnya 67sudah dikonsumsi saat menemukan kecocokan pertama. Anda dapat menggunakan lookahead positif untuk memeriksa keberadaan teks tanpa benar-benar "melahapnya" (yaitu menambahkan kecocokan):

/>>>\d+\s(.*?)(?=>>>)/g

Lihat menghasilkan demo regex onlinetext1 dan text2sebagai konten Grup 1 ditemukan.

Lihat juga Cara mendapatkan semua kecocokan yang mungkin tumpang tindih untuk sebuah string .

Pertimbangan kinerja

Pola pencocokan titik malas ( .*?) di dalam pola regex dapat memperlambat eksekusi skrip jika input yang sangat panjang diberikan. Dalam banyak kasus, teknik membuka gulungan-the-loop membantu untuk tingkat yang lebih besar. Mencoba mengambil semua antara cowdan milkdari "Their\ncow\ngives\nmore\nmilk", kita melihat bahwa kita hanya perlu mencocokkan semua baris yang tidak dimulai dengan milk, jadi, alih-alih cow\n([\s\S]*?)\nmilkkita dapat menggunakan:

/cow\n(.*(?:\n(?!milk$).*)*)\nmilk/gm

Lihat demo regex (jika ada \r\n, gunakan /cow\r?\n(.*(?:\r?\n(?!milk$).*)*)\r?\nmilk/gm). Dengan string uji kecil ini, peningkatan kinerja dapat diabaikan, tetapi dengan teks yang sangat besar, Anda akan merasakan perbedaannya (terutama jika garisnya panjang dan garis putus tidak terlalu banyak).

Contoh penggunaan regex dalam 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);

Menggunakan String#matchAllmetode modern

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

Berikut adalah regex yang akan mengambil apa yang ada di antara sapi dan susu (tanpa spasi di depan / belakang):

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

Contoh: http://jsfiddle.net/entropo/tkP74/


17
  • Anda perlu menangkap .*
  • Anda dapat (tetapi tidak harus) membuat .*nongreedy
  • Benar-benar tidak perlu untuk lookahead.

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

Dalam contoh khusus ini, jika serakah itu akan mencapai akhir dan mundur (mungkin).
Ben

9

Jawaban yang dipilih tidak berhasil untuk saya ... hmm ...

Tambahkan saja ruang setelah sapi dan / atau sebelum ASI untuk mengurangi ruang dari "selalu memberi"

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

masukkan deskripsi gambar di sini


Anda tidak perlu mengomentari jawaban Anda sendiri, cukup sunting.
Cody G

Look Behind ?<=tidak didukung dalam Javascript.
Mark Carpenter Jr

@MarkCarpenterJr jika Anda mengujinya melalui regextester.com , Anda akan mendapatkan petunjuk itu. Tampaknya situs tersebut mendasarkan aturannya dari spesifikasi yang lebih lama. Lookbehind sekarang didukung. Lihat stackoverflow.com/questions/30118815/... Dan polanya bekerja dengan baik dengan browser modern tanpa kesalahan. Coba checker ini sebagai gantinya regex101.com
duduwe

@ CodyG.ah ya. mengerti.
duduwe

8

Saya bisa mendapatkan apa yang saya butuhkan menggunakan solusi Martinho Fernandes di bawah ini. Kode tersebut adalah:

var test = "My cow always gives milk";

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

Anda akan melihat bahwa saya memberi tahu variabel testRE sebagai sebuah array. Ini karena testRE kembali sebagai array, untuk beberapa alasan. Output dari:

My cow always gives milk

Perubahan menjadi:

always gives

1
Terima kasih, saya menambahkan biola ( jsfiddle.net/MoscaPt/g5Lngjx8/2 ) untuk itu. / Johan
Mosca Pt

4

Cukup gunakan ekspresi reguler berikut:

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

Look Behind ?<=tidak didukung dalam Javascript. Akan menjadi cara untuk melakukannya.
Mark Carpenter Jr

Ini didukung dalam JavaScript. Itu tidak didukung di Safari dan Mozilla (belum), hanya di Chrome dan Opera.
Paul Strupeikis

3

Saya menemukan regex menjadi membosankan dan memakan waktu mengingat sintaksis. Karena Anda sudah menggunakan javascript, lebih mudah melakukan hal berikut tanpa 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
Bekerja untukku! jawaban yang fantastis karena itu sangat sederhana! :)
Andrew Irwin


0

Pencocokan metode () mencari string untuk kecocokan dan mengembalikan objek 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

Tugas

Ekstrak substring di antara dua string (tidak termasuk dua string ini)

Larutan

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]);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.