JavaScript regex flag multiline tidak berfungsi

265

Saya menulis regex untuk mengambil string dari HTML, tetapi tampaknya bendera multiline tidak berfungsi.

Ini adalah pola saya dan saya ingin mendapatkan teks dalam h1tag.

var pattern= /<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/mi
m = html.search(pattern);
return m[1];

Saya membuat string untuk mengujinya. Ketika string berisi "\ n", hasilnya selalu nol. Jika saya menghapus semua "\ n", itu memberi saya hasil yang tepat, tidak masalah dengan atau tanpa /mbendera.

Apa yang salah dengan regex saya?

Peter Mortensen
sumber
14
Jangan gunakan ekspresi reguler untuk mem-parsing HTML, HTML BUKAN bahasa biasa. Gunakan parser HTML, resp. DOM. Itu juga jauh lebih sederhana.
Svante
Anda sedang mencari DOTALL, bukan multiline.
Vanuan
Perhatikan bahwa JavaScript akan segera memiliki satu dotAllpengubah sehingga Anda dapat melakukan /.../sdan titik-titik Anda juga akan cocok baris baru. Pada Juli 2017 berada di belakang bendera di Chrome.

Jawaban:

609

Anda mencari /.../spengubah, juga dikenal sebagai pengubah dotall . Ini memaksa titik .untuk juga cocok dengan baris baru, yang tidak dilakukan secara default.

Berita buruknya adalah ia tidak ada di JavaScript (tidak seperti pada ES2018, lihat di bawah) . Berita baiknya adalah Anda dapat mengatasinya dengan menggunakan kelas karakter (mis. \s) Dan negasi ( \S) bersama-sama, seperti ini:

[\s\S]

Jadi dalam kasus Anda regex akan menjadi:

/<div class="box-content-5">[\s\S]*<h1>([^<]+?)<\/h1>/i

Pada ES2018, JavaScript mendukung sflag (dotAll), jadi di lingkungan modern ekspresi reguler Anda bisa seperti saat Anda menulisnya, tetapi dengan sflag di bagian akhir (alih-alih m; mmengubah cara ^dan $kerja, tidak .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
Molf
sumber
5
@simo Mencocokkan karakter spasi putih atau non spasi putih, secara efektif cocok dengan karakter apa pun. Itu seperti ., tetapi mencocokkan spasi putih juga ( \s) berarti cocok \n(yang .tidak dilakukan dalam JavaScript, atau dapat dilakukan dengan sbendera).
alex
1
Jawaban ini telah ditambahkan ke FAQ Ekspresi Reguler Overflow Overflow , di bawah "Pengubah".
aliteralmind
40
Menurut MDN, [^]juga berfungsi untuk mencocokkan karakter apa pun, termasuk baris baru, dalam JavaScript. Lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen
6
Untuk masalah kinerja, sangat disarankan untuk menggunakan *?quantifier alih-alih *untuk menghindari keserakahan. Ini akan menghindari penangkapan terakhir <h1> dokumen: itu mungkin bukan apa yang Anda inginkan dan itu tidak efisien karena regexp akan terus mencari <h1> sampai akhir string bahkan jika itu telah ditemukan sebelumnya.
KrisWebDev
9
Versi [^] lebih mudah pada kompiler regexp, dan juga lebih singkat.
Erik Corry
21

Anda menginginkan spengubah (dotall), yang tampaknya tidak ada dalam Javascript - Anda dapat menggantinya .dengan [\ s \ S] seperti yang disarankan oleh @molf. The m(multiline) merek pengubah ^ dan $ jalur pertandingan daripada seluruh string.

Greg
sumber
4
Anda dapat menambahkan bahwa / s "modifier menetapkan mode singleline sebagai lawan dari mode multiline. +1
Cerebrus
Sembilan tahun kemudian, JavaScript sekarang memiliki sbendera (ES2018). :-)
TJ Crowder
12

[\s\S]tidak bekerja untuk saya di nodejs 6.11.3. Berdasarkan dokumentasi RegExp , dikatakan menggunakan [^]yang berfungsi untuk saya.

(Titik, titik desimal) cocok dengan karakter tunggal apa pun kecuali terminator baris: \ n, \ r, \ u2028 atau \ u2029.

Di dalam set karakter, titik kehilangan makna khusus dan cocok dengan titik literal.

Perhatikan bahwa flag m multiline tidak mengubah perilaku dot. Jadi untuk mencocokkan pola di beberapa baris, set karakter [^] dapat digunakan (jika Anda tidak bermaksud versi IE yang lama, tentu saja), itu akan cocok dengan karakter apa pun termasuk baris baru.

Sebagai contoh:

/This is on line 1[^]*?This is on line 3/m

Dimana *? adalah ambil tanpa-serakah dari 0 atau lebih kejadian [^].

Michael Grant
sumber
1
Bagi mereka yang bertanya-tanya apa [^]artinya: itu seperti negasi ganda: "cocokkan karakter apa pun yang tidak ada dalam daftar kosong ini " dan karenanya dikatakan "cocokkan karakter apa pun" .
trincot
8

Pengubah dotall sebenarnya telah membuatnya menjadi JavaScript pada Juni 2018, yaitu ECMAScript 2018.
https://github.com/tc39/proposal-regexp-dotall-flag

const re = /foo.bar/s; // Or, `const re = new RegExp('foo.bar', 's');`.
re.test('foo\nbar');
// → true
re.dotAll
// → true
re.flags
// → 's'
Forivin
sumber
0

Saran saya adalah bahwa lebih baik untuk memisahkan string multi-line dengan "\ n" dan menggabungkan pemisahan dari string asli dan menjadi satu baris dan mudah untuk dimanipulasi.

<textarea class="form-control" name="Body" rows="12" data-rule="required" 
                  title='@("Your feedback ".Label())'
                  placeholder='@("Your Feedback here!".Label())' data-val-required='@("Feedback is required".Label())'
                  pattern="^[0-9a-zA-Z ,;/?.\s_-]{3,600}$" data-val="true" required></textarea>


$( document ).ready( function() {
  var errorMessage = "Please match the requested format.";
  var firstVisit = false;

  $( this ).find( "textarea" ).on( "input change propertychange", function() {

    var pattern = $(this).attr( "pattern" );
    var element = $( this );

    if(typeof pattern !== typeof undefined && pattern !== false)
    {
      var ptr = pattern.replace(/^\^|\$$/g, '');
      var patternRegex = new RegExp('^' + pattern.replace(/^\^|\$$/g, '') + '$', 'gm');     

      var ks = "";
      $.each($( this ).val().split("\n"), function( index, value ){
        console.log(index + "-" + value);
        ks += " " + value;
      });      
      //console.log(ks);

      hasError = !ks.match( patternRegex );
      //debugger;

      if ( typeof this.setCustomValidity === "function") 
      {
        this.setCustomValidity( hasError ? errorMessage : "" );
      } 
      else 
      {
        $( this ).toggleClass( "invalid", !!hasError );
        $( this ).toggleClass( "valid", !hasError );

        if ( hasError ) 
        {
          $( this ).attr( "title", errorMessage );
        } 
        else
        {
          $( this ).removeAttr( "title" );
        }
      }
    }

  });
});
Ghebrehiywet
sumber