Il flag multilinea regex JavaScript non funziona


265

Ho scritto una regex per recuperare la stringa dall'HTML, ma sembra che il flag multilinea non funzioni.

Questo è il mio modello e voglio ottenere il testo nel h1tag.

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

Ho creato una stringa per testarla. Quando la stringa contiene "\ n", il risultato è sempre nullo. Se avessi rimosso tutti i "\ n", mi avrebbe dato il risultato giusto, non importa con o senza la /mbandiera.

Cosa c'è che non va nel mio regex?


14
Non utilizzare espressioni regolari per analizzare HTML, HTML NON è un linguaggio normale. Utilizzare un parser HTML, resp. il DOM. Anche questo è molto più semplice.
Svante,

Stai cercando DOTALL, non multilinea.
Vanuan,

Nota che JavaScript avrà presto il dotAllmodificatore in modo che tu possa fare /.../se anche i tuoi punti corrisponderanno a nuove linee. A partire da luglio 2017 è dietro una bandiera in Chrome.

Risposte:


609

Stai cercando il /.../smodificatore, noto anche come modificatore dotall . Forza il punto .a corrispondere anche alle nuove righe, cosa che non fa di default.

La cattiva notizia è che non esiste in JavaScript (lo fa a partire da ES2018, vedi sotto) . La buona notizia è che puoi aggirarlo usando una classe di caratteri (ad esempio \s) e la sua negazione ( \S) insieme, in questo modo:

[\s\S]

Quindi nel tuo caso il regex diventerebbe:

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

A partire da ES2018, JavaScript supporta il sflag (dotAll), quindi in un ambiente moderno la tua espressione regolare potrebbe essere come l'hai scritta, ma con un sflag alla fine (piuttosto che m; mcambia come ^e $funziona, non .):

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

5
@simo Corrisponde a qualsiasi carattere di spazi bianchi o non di spazi bianchi, abbinando efficacemente qualsiasi carattere. È come ., ma anche la corrispondenza degli spazi bianchi ( \s) significa che corrisponde \n(che .non funziona in JavaScript, o può essere fatto a che fare con la sbandiera).
alex

1
Questa risposta è stata aggiunta alle Domande frequenti sull'espressione regolare dello stack overflow , in "Modificatori".
aliteralmind

40
Secondo MDN, [^]funziona anche per abbinare qualsiasi carattere, comprese le nuove righe, in JavaScript. Vedi developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen

6
Per problemi di prestazioni, si consiglia vivamente di utilizzare il *?quantificatore invece di *evitare l'avidità. Questo eviterà di catturare l' ultimo <h1> del documento: probabilmente non è quello che vuoi e non è efficiente in quanto il regexp continuerà a cercare <h1> fino alla fine della stringa anche se lo ha già trovato prima.
KrisWebDev il

9
La versione [^] è molto più semplice sul compilatore regexp e anche più concisa.
Erik Corry,

21

Volete il smodificatore (dotall), che apparentemente non esiste in Javascript - potete sostituirlo .con [\ s \ S] come suggerito da @molf. Il mmodificatore (multilinea) rende ^ e $ le linee di corrispondenza anziché l'intera stringa.


4
Potresti aggiungere che il modificatore / s "imposta la modalità
single line invece della

Nove anni dopo, JavaScript ora ha la sbandiera (ES2018). :-)
TJ Crowder,

12

[\s\S]non ha funzionato per me in nodejs 6.11.3. Sulla base della documentazione di RegExp , dice di usare [^]ciò che funziona per me.

(Il punto, il punto decimale) corrisponde a qualsiasi carattere singolo tranne i terminatori di riga: \ n, \ r, \ u2028 o \ u2029.

All'interno di un set di caratteri, il punto perde il suo significato speciale e corrisponde a un punto letterale.

Si noti che il flag multilinea m non modifica il comportamento del punto. Quindi, per abbinare uno schema su più linee, è possibile utilizzare il set di caratteri [^] (se non intendi una vecchia versione di IE, ovviamente), corrisponderà a qualsiasi carattere, comprese le nuove linee.

Per esempio:

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

dove la *? è la presa non avida di 0 o più occorrenze di [^].


1
Per coloro che si chiedono cosa [^]significhi: è come una doppia negazione: "abbina qualsiasi personaggio che non è in questa lista vuota " e quindi si riduce a dire "abbina qualsiasi personaggio" .
trincot,


0

Il mio suggerimento è che è meglio dividere la stringa a più righe con "\ n" e concatenare le divisioni della stringa originale e diventare una riga singola e facile da manipolare.

<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" );
        }
      }
    }

  });
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.