Das mehrzeilige JavaScript-Regex-Flag funktioniert nicht

265

Ich habe einen regulären Ausdruck geschrieben, um Zeichenfolgen aus HTML abzurufen, aber es scheint, dass das mehrzeilige Flag nicht funktioniert.

Dies ist mein Muster und ich möchte den Text in h1Tag bekommen.

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

Ich habe einen String erstellt, um ihn zu testen. Wenn die Zeichenfolge "\ n" enthält, ist das Ergebnis immer null. Wenn ich alle "\ n" entfernt habe, habe ich das richtige Ergebnis erzielt, egal mit oder ohne /mFlagge.

Was ist los mit meiner Regex?

Peter Mortensen
quelle
14
Verwenden Sie keine regulären Ausdrücke, um HTML zu analysieren. HTML ist KEINE reguläre Sprache. Verwenden Sie einen HTML-Parser bzw. das DOM. Das ist auch viel einfacher.
Svante
Sie suchen DOTALL, nicht mehrzeilig.
Vanuan
Beachten Sie, dass JavaScript bald den dotAllModifikator haben wird, damit Sie dies tun können, /.../sund Ihre Punkte auch mit neuen Zeilen übereinstimmen. Ab Juli 2017 steht es hinter einer Flagge in Chrome.

Antworten:

609

Sie suchen nach dem /.../sModifikator, der auch als Dotall- Modifikator bezeichnet wird. Es erzwingt, dass der Punkt .auch mit Zeilenumbrüchen übereinstimmt, was standardmäßig nicht der Fall ist .

Die schlechte Nachricht ist, dass es in JavaScript nicht vorhanden ist (ab ES2018, siehe unten) . Die gute Nachricht ist, dass Sie es umgehen können, indem Sie eine Zeichenklasse (z. B. \s) und ihre Negation ( \S) zusammen verwenden, wie folgt :

[\s\S]

In Ihrem Fall würde der reguläre Ausdruck also werden:

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

Ab ES2018 unterstützt JavaScript das sFlag (dotAll). In einer modernen Umgebung kann Ihr regulärer Ausdruck also so sein, wie Sie ihn geschrieben haben, jedoch mit einem sFlag am Ende (anstatt m; mändert, wie ^und $funktioniert, nicht .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
molf
quelle
5
@simo Entspricht einem beliebigen Leerzeichen oder Nicht-Leerzeichen und entspricht praktisch jedem Zeichen. Es ist wie ., aber ein übereinstimmendes Leerzeichen ( \s) bedeutet, dass es übereinstimmt \n(was .in JavaScript nicht funktioniert oder mit dem sFlag zu tun hat ).
Alex
1
Diese Antwort wurde zu den häufig gestellten Fragen zum Stapelüberlauf für reguläre Ausdrücke unter "Modifikatoren" hinzugefügt .
Aliteralmind
40
Funktioniert laut MDN [^]auch für alle Zeichen, einschließlich Zeilenumbrüche, in JavaScript. Siehe developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen
6
Bei Leistungsproblemen wird dringend empfohlen, den *?Quantifizierer anstelle zu *verwenden, um Gier zu vermeiden. Auf diese Weise wird vermieden, dass das letzte <h1> des Dokuments abgefangen wird: Dies ist wahrscheinlich nicht das, was Sie möchten, und dies ist nicht effizient, da der reguläre Ausdruck bis zum Ende der Zeichenfolge weiterhin nach <h1> sucht, selbst wenn er es bereits zuvor gefunden hat.
KrisWebDev
9
Die [^] Version ist für den Regexp-Compiler viel einfacher und auch knapper.
Erik Corry
21

Sie möchten den sModifikator (dotall), der in Javascript anscheinend nicht vorhanden ist - Sie können ihn durch .[\ s \ S] ersetzen, wie von @molf vorgeschlagen. Mit dem mModifikator (mehrzeilig) werden die Zeilen ^ und $ und nicht die gesamte Zeichenfolge abgeglichen.

Greg
quelle
4
Sie können hinzufügen, dass der Modifikator / s "den Singleline-Modus im Gegensatz zum Multiline-Modus
festlegt
Neun Jahre später hat JavaScript jetzt die sFlagge (ES2018). :-)
TJ Crowder
12

[\s\S]hat bei mir in nodejs 6.11.3 nicht funktioniert. Basierend auf der RegExp-Dokumentation heißt es zu verwenden, [^]was für mich funktioniert.

(Der Punkt, der Dezimalpunkt) entspricht einem einzelnen Zeichen mit Ausnahme der Zeilenabschlüsse: \ n, \ r, \ u2028 oder \ u2029.

Innerhalb eines Zeichensatzes verliert der Punkt seine besondere Bedeutung und entspricht einem wörtlichen Punkt.

Beachten Sie, dass das mehrzeilige Flag m das Punktverhalten nicht ändert. Um ein Muster über mehrere Zeilen hinweg abzugleichen, kann der Zeichensatz [^] verwendet werden (wenn Sie natürlich keine alte Version von IE meinen). Er stimmt mit jedem Zeichen überein, einschließlich Zeilenumbrüchen.

Beispielsweise:

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

bei dem die *? ist das nicht gierige Ergreifen von 0 oder mehr Vorkommen von [^].

Michael Grant
quelle
1
Für diejenigen, die sich fragen, was das [^]bedeutet: Es ist wie eine doppelte Negation: "Entspricht einem beliebigen Zeichen, das nicht in dieser leeren Liste enthalten ist", und es kommt darauf an, "Entspricht einem beliebigen Zeichen" zu sagen .
Trincot
8

Der Dotall-Modifikator hat es im Juni 2018 tatsächlich in JavaScript geschafft, dh in 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
quelle
0

Mein Vorschlag ist, dass es besser ist, die mehrzeilige Zeichenfolge mit "\ n" zu teilen und die Teilungen der ursprünglichen Zeichenfolge zu verketten, um eine einzelne Zeile zu erhalten und einfach zu bearbeiten.

<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
quelle