Bagaimana cara menggunakan regex JavaScript melalui beberapa baris?

275
var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre.*?<\/pre>/gm );
alert(arr);     // null

Saya ingin blok PRE diambil, meskipun itu mencakup karakter baris baru. Saya pikir bendera 'm' melakukannya. Tidak.

Temukan jawabannya di sini sebelum memposting. Karena saya pikir saya tahu JavaScript (baca tiga buku, jam kerja) dan tidak ada solusi di SO, saya akan berani memposting. lempar batu di sini

Jadi solusinya adalah:

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[\s\S]*?<\/pre>/gm );
alert(arr);     // <pre>...</pre> :)

Adakah yang memiliki cara yang kurang samar?

Sunting: ini duplikat tetapi karena lebih sulit ditemukan daripada milik saya, saya tidak menghapus.

Ini mengusulkan [^]sebagai "titik multiline". Apa yang masih saya tidak mengerti adalah mengapa [.\n]tidak berhasil. Kira ini adalah salah satu bagian sedih dari JavaScript ..

aliasuppi
sumber
29
Regex yang lebih samar? Tidak mungkin, secara alami.
Rubens Farias
btw, Anda harus membaca: "Parsing Html: The Cthulhu Way" codinghorror.com/blog/archives/001311.html
Rubens Farias
1
Tautan berubah dari komentar sebelumnya: blog.codinghorror.com/parsing-html-the-cthulhu-way (5yrs-ish later)
dab

Jawaban:

248

[.\n]tidak berfungsi karena .tidak memiliki makna khusus di dalamnya [], itu hanya berarti literal .. (.|\n)akan menjadi cara untuk menentukan "karakter apa pun, termasuk baris baru". Jika Anda ingin mencocokkan semua baris, Anda akan perlu menambahkan \rjuga untuk menyertakan Windows dan Mac OS klasik akhir baris gaya: (.|[\r\n]).

Itu ternyata agak rumit, juga lambat, (lihat jawaban KrisWebDev untuk detailnya ), jadi pendekatan yang lebih baik adalah mencocokkan semua karakter spasi putih dan semua karakter non-spasi putih, dengan [\s\S], yang akan cocok dengan semuanya, dan lebih cepat dan lebih lebih sederhana.

Secara umum, Anda tidak harus mencoba menggunakan regexp untuk mencocokkan tag HTML yang sebenarnya. Lihat, misalnya, pertanyaan - pertanyaan ini untuk informasi lebih lanjut tentang alasannya.

Alih-alih, cobalah mencari DOM untuk tag yang Anda butuhkan (menggunakan jQuery membuat ini lebih mudah, tetapi Anda selalu dapat melakukannya document.getElementsByTagName("pre")dengan DOM standar), lalu mencari konten teks dari hasil tersebut dengan regexp jika Anda perlu mencocokkan dengan konten .

Brian Campbell
sumber
Apa yang saya lakukan adalah membuat .wiki -> Konversi HTML dengan cepat, menggunakan JavaScript. Karena itu, saya belum memiliki DOM. Sebagian besar file Wiki adalah sintaksnya sendiri, tetapi saya mengizinkan tag HTML untuk digunakan jika diperlukan. Saran Anda sangat valid, jika saya berurusan dengan DOM dengan ini. Terima kasih. :)
akauppi
Cukup adil. Saya kira itu adalah alasan yang valid untuk ingin menggunakan regex pada HTML, meskipun sintaks wiki yang dicampur dengan HTML dapat memiliki semua jenis kotak sudut yang menyenangkan itu sendiri.
Brian Campbell
2
[\r\n]diterapkan pada urutan \ r \ n, pertama-tama akan cocok dengan \ r dan kemudian \ n. Jika Anda ingin mencocokkan seluruh urutan sekaligus, terlepas dari apakah urutan itu \ r \ n atau hanya \ n, gunakan pola.|\r?\n
Eirik Birkeland
1
Untuk mencocokkan seluruh string multiline, coba serakah [\s\S]+.
Boaz
Saya hanya ingin menambahkan untuk anak cucu yang JS sintaks regex mengabaikan makna .dalam []adalah berbeda dari kerangka kerja regex lain, khususnya yang maju di NET. Teman-teman, tolong jangan berasumsi bahwa regex adalah lintas platform, mereka sering tidak !!
Tn. TA
330

JANGAN gunakan (.|[\r\n])bukan .untuk pencocokan multiline.

LAKUKAN gunakan [\s\S]alih-alih .untuk pencocokan multiline

Juga, hindari keserakahan di mana tidak diperlukan dengan menggunakan *?atau +?mengukur bukan *atau +. Ini dapat memiliki dampak kinerja yang sangat besar.

Lihat patokan yang telah saya buat: http://jsperf.com/javascript-multiline-regexp-workarounds

Using [^]: fastest
Using [\s\S]: 0.83% slower
Using (.|\r|\n): 96% slower
Using (.|[\r\n]): 96% slower

NB: Anda juga dapat menggunakan [^]tetapi sudah usang dalam komentar di bawah ini.

KrisWebDev
sumber
22
Poin bagus, tapi saya tetap menyarankan untuk tidak menggunakannya [^]. Di satu sisi, JavaScript adalah satu-satunya rasa yang saya tahu yang mendukung idiom itu, dan bahkan ada yang digunakan di tempat dekat sesering [\s\S]. Di sisi lain, sebagian besar citarasa lain memungkinkan Anda melarikan diri ]dengan mendaftar terlebih dahulu. Dengan kata lain, dalam JavaScript [^][^]cocok dengan dua karakter, tapi di NET itu cocok dengan salah satu karakter selain ], [atau ^.
Alan Moore
1
Bagaimana Anda tahu bahwa itu \Sakan cocok \ratau \nberlawanan dengan beberapa karakter lain?
Gili
3
Lihat pertanyaan ini untuk perincian. Ini adalah retasan untuk mencocokkan semua karakter spasi putih + semua karakter non-spasi putih = semua karakter. Lihat juga MDN untuk dokumentasi karakter khusus regexp.
KrisWebDev
4
Ada alasan untuk lebih menyukai [\s\S]orang lain, seperti [\d\D]atau [\w\W]?
Phrogz
1
Izinkan saya dengan cepat menunjukkan bahwa pengujian Anda untuk operator serakah telah dicurangi. /<p>Can[^]*?<\/p>/tidak cocok dengan konten yang sama dengan /<p>Can[^]*<\/p>/. Varian serakah harus diubah /<p>(?:[^<]|<(?!\/p>))*<\/p>/agar sesuai dengan konten yang sama.
3limin4t0r
19

Anda tidak menentukan lingkungan dan versi Javascript (ECMAscript) Anda, dan saya menyadari bahwa postingan ini berasal dari 2009, tetapi hanya untuk kelengkapan, dengan rilis ECMA2018 sekarang kita dapat menggunakan sbendera yang menyebabkan .kecocokan '\ n', lihat https : //stackoverflow.com/a/36006948/141801

Jadi:

let s = 'I am a string\nover several\nlines.';
console.log('String: "' + s + '".');

let r = /string.*several.*lines/s; // Note 's' modifier
console.log('Match? ' + r.test(s); // 'test' returns true

Ini adalah tambahan baru-baru ini dan tidak akan berfungsi di banyak lingkungan saat ini, misalnya Node v8.7.0 tampaknya tidak mengenalinya, tetapi bekerja di Chromium, dan saya menggunakannya dalam uji tulis naskah yang saya tulis dan mungkin itu akan menjadi lebih utama seiring berjalannya waktu.

Neek
sumber
1
Ini berfungsi baik di Chrome (v67) tetapi benar-benar memecah regex (juga berhenti bekerja baris demi baris) di IE11 dan IEdge (v42)
freedomn-m
Terima kasih @ freedomn-m .. IE tidak mendukung fitur yang sangat baru hampir sepenuhnya tidak mengejutkan :) Tapi ya, perlu disebutkan di mana itu tidak berhasil menyelamatkan siapa pun yang mencoba 'men-debug' mengapa upaya mereka untuk menggunakannya tidak berfungsi seperti yang diharapkan.
Neek
11

[.\n]tidak berfungsi, karena titik dalam [](menurut definisi regex; bukan hanya javascript) berarti karakter titik. Anda dapat menggunakan (.|\n)(atau (.|[\n\r])) sebagai gantinya.

Y. Shoham
sumber
24
[\s\S]adalah idiom JavaScript paling umum untuk mencocokkan semuanya termasuk baris baru. Ini lebih mudah pada mata dan jauh lebih efisien daripada pendekatan berbasis alternatif seperti (.|\n). (Secara harfiah berarti "setiap karakter yang merupakan spasi putih atau karakter apa pun yang bukan spasi putih).
Alan Moore
2
Anda benar, tetapi pertanyaannya adalah tentang .dan \n, dan mengapa [.\n]tidak berhasil. Seperti disebutkan dalam pertanyaan, pendekatan [^]ini juga bagus.
Y. Shoham
6

Saya telah mengujinya (Chrome) dan itu berfungsi untuk saya (keduanya [^]dan [^\0]), dengan mengubah titik ( .) dengan salah satu [^\0]atau [^], karena titik tidak cocok dengan jeda baris (Lihat di sini:http://www.regular-expressions.info/dot.html ).

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[^\0]*?<\/pre>/gm );
alert(arr);     //Working

Hzzkygcs
sumber
1
Masalahnya [^\0]adalah bahwa itu tidak akan cocok dengan karakter nol meskipun karakter nol diizinkan dalam string Javascript (lihat jawaban ini ).
Donald Duck
0

Selain contoh-contoh di atas, ini merupakan alternatif.

^[\\w\\s]*$

Di mana \wuntuk kata-kata dan \suntuk ruang putih

azhar22k
sumber