Znacznik wielowierszowy JavaScript regex nie działa


265

Napisałem wyrażenie regularne, aby pobrać ciąg znaków z HTML, ale wygląda na to, że flaga multilinii nie działa.

To jest mój wzór i chcę uzyskać tekst w h1tagu.

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

Utworzyłem ciąg, aby go przetestować. Gdy ciąg zawiera „\ n”, wynik jest zawsze pusty. Jeśli usunąłem wszystkie „\ n”, uzyskałem właściwy wynik, bez względu na /mflagę lub bez .

Co jest nie tak z moim wyrażeniem regularnym?


14
Nie używaj wyrażeń regularnych do analizowania HTML, HTML NIE jest zwykłym językiem. Użyj parsera HTML lub. DOM. To również jest o wiele prostsze.
Svante

Szukasz DOTALL, a nie multilinii.
Vanuan

Zauważ, że JavaScript wkrótce mają się dotAllmodyfikator tak można zrobić /.../si twoje punkty zostaną również dopasować nowe linie. Od lipca 2017 r. Jest za flagą w Chrome.

Odpowiedzi:


609

Szukasz /.../smodyfikatora, znanego również jako modyfikator dotall . Zmusza kropkę .do dopasowywania także nowych linii, czego domyślnie nie robi .

Zła wiadomość jest taka, że nie istnieje ona w JavaScript (tak jak w ES2018, patrz poniżej) . Dobrą wiadomością jest to, że możesz obejść ten problem, używając klasy znaków (np. \s) I jej negacji ( \S) razem, jak poniżej:

[\s\S]

Więc w twoim przypadku regex stałby się:

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

Począwszy od ES2018, JavaScript obsługuje sflagę (dotAll), więc w nowoczesnym środowisku wyrażenie regularne może wyglądać tak, jak zostało napisane, ale z sflagą na końcu (zamiast m; mzmienia, jak ^i $działa, nie .):

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

5
@simo Dopasuj dowolny biały lub inny znak, skutecznie dopasowując dowolny znak. To tak ., ale dopasowanie również białych znaków ( \s) oznacza, że ​​pasuje \n(co .nie działa w JavaScript lub można zrobić z sflagą).
alex

1
Ta odpowiedź została dodana do FAQ wyrażeń regularnych przepełnienia stosu , w sekcji „Modyfikatory”.
aliteralmind

40
Według MDN [^]działa również w JavaScript w celu dopasowania dowolnego znaku, w tym nowego wiersza. Zobacz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen

6
W przypadku problemów z wydajnością zaleca się stosowanie *?kwantyfikatora zamiast *w celu uniknięcia zachłanności. Pozwoli to uniknąć przechwycenia ostatniego <h1> dokumentu: prawdopodobnie nie jest to pożądane i nie jest wydajne, ponieważ wyrażenie regularne będzie szukało <h1> do końca ciągu, nawet jeśli już go wcześniej znalazło.
KrisWebDev

9
Wersja [^] jest znacznie łatwiejsza w kompilatorze wyrażeń regularnych, a także bardziej zwięzła.
Erik Corry,

21

Chcesz smodyfikatora (dotall), który najwyraźniej nie istnieje w Javascript - możesz go zastąpić .[\ s \ S], jak sugeruje @molf. W m(multiline) modyfikator marki ^ i $ linie mecz, a nie cały ciąg.


4
Możesz dodać, że modyfikator / s ustawia tryb pojedynczej linii w przeciwieństwie do trybu wielowierszowego. +1
Cerebrus

Dziewięć lat później JavaScript ma teraz sflagę (ES2018). :-)
TJ Crowder

12

[\s\S]nie działało dla mnie w nodejs 6.11.3. Opierając się na dokumentacji RegExp , mówi, aby użyć, [^]który działa dla mnie.

(Kropka, kropka dziesiętna) odpowiada dowolnemu pojedynczemu znakowi oprócz zakończeń linii: \ n, \ r, \ u2028 lub \ u2029.

Wewnątrz zestawu znaków kropka traci swoje specjalne znaczenie i pasuje do dosłownej kropki.

Zauważ, że flaga multilinii m nie zmienia zachowania kropek. Aby dopasować wzór do wielu wierszy, można użyć zestawu znaków [^] (jeśli oczywiście nie masz na myśli starej wersji IE), dopasuje on dowolny znak, w tym nowe linie.

Na przykład:

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

gdzie *? jest niechcianym chwytaniem 0 lub więcej wystąpień [^].


1
Dla tych, którzy zastanawiają się, co [^]oznacza: to jest jak podwójna negacja: „dopasuj dowolny znak, który nie znajduje się na tej pustej liście”, a więc sprowadza się do powiedzenia „dopasuj dowolny znak” .
trincot


0

Moja sugestia jest taka, że ​​lepiej jest podzielić wieloliniowy ciąg znaków za pomocą „\ n” i połączyć podziały oryginalnego łańcucha i stać się pojedynczą linią i łatwą do manipulowania.

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

  });
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.