Многострочный флаг регулярного выражения JavaScript не работает

265

Я написал регулярное выражение для извлечения строки из HTML, но кажется, что многострочный флаг не работает.

Это мой шаблон, и я хочу получить текст в h1теге.

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

Я создал строку, чтобы проверить это. Когда строка содержит «\ n», результат всегда будет нулевым. Если я удалил все "\ n", это дало бы мне правильный результат, независимо от того, был или нет /mфлаг.

Что не так с моим регулярным выражением?

Питер Мортенсен
источник
14
Не используйте регулярные выражения для разбора HTML, HTML НЕ является обычным языком. Используйте анализатор HTML, соответственно ДОМ. Это также намного проще.
Сванте
Вы ищете ДОТАЛ, а не многострочный.
Вануан
Обратите внимание, что в скором времени в JavaScript появитсяdotAll модификатор, так что вы можете сделать это, /.../sи ваши точки также будут соответствовать новым строкам. По состоянию на июль 2017 года он стоит за флагом в Chrome.

Ответы:

609

Вы ищете /.../sмодификатор, также известный как модификатор dotall . Это заставляет точку .также соответствовать символам новой строки, что по умолчанию не выполняется .

Плохая новость заключается в том, что он не существует в JavaScript (он существует на ES2018, см. Ниже) . Хорошей новостью является то, что вы можете обойти это, используя вместе класс символов (например \s) и его отрицание ( \S), например так:

[\s\S]

Так что в вашем случае регулярное выражение станет:

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

На ES2018, JavaScript поддерживает sфлаг (dotAll), так и в современных условиях регулярное выражение может быть , как вы написали, но с sфлагом в конце (а не m; mизменения , как ^и $работа, не .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
Molf
источник
5
@simo Совпадает с любым пробелом или непробельным символом, эффективно сопоставляя любой символ. Это так ., но совпадение с пробелами тоже ( \s) означает, что оно совпадает \n(что .не выполняется в JavaScript или может быть связано с sфлагом).
Алекс
1
Этот ответ был добавлен в FAQ по регулярным выражениям Stack Overflow в разделе «Модификаторы».
aliteralmind
40
Согласно MDN, [^]также работает, чтобы соответствовать любому символу, включая символы новой строки, в JavaScript. См. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Дэн Аллен
6
Для проблем с производительностью настоятельно рекомендуется использовать *?квантификатор вместо *того, чтобы избежать жадности. Это позволит избежать перехвата последнего <h1> документа: это, вероятно, не то, что вам нужно, и это неэффективно, поскольку регулярное выражение будет продолжать искать <h1> до конца строки, даже если оно уже нашло его ранее.
KrisWebDev
9
Версия [^] намного проще для компилятора регулярных выражений, а также более краткая.
Эрик Корри
21

Вам нужен sмодификатор (dotall), которого, очевидно, нет в Javascript - вы можете заменить его .на [\ s \ S], как предложено @molf. В m(многострочных) модификаторы позволяет ^ и $ спичечных линий , а не вся строка.

Greg
источник
4
Вы можете добавить, что модификатор / s устанавливает однострочный режим, а не многострочный. +1
Cerebrus
Девять лет спустя, JavaScript теперь имеет sфлаг (ES2018). :-)
TJ Crowder
12

[\s\S]у меня не работало в nodejs 6.11.3. Основываясь на документации RegExp , он говорит, что использовать, [^]который работает для меня.

(Точка, десятичная точка) соответствует любому отдельному символу, кроме ограничителей строки: \ n, \ r, \ u2028 или \ u2029.

Внутри набора символов точка теряет свое особое значение и соответствует буквальной точке.

Обратите внимание, что многострочный флаг m не меняет поведение точек. Таким образом, чтобы сопоставить шаблон с несколькими строками, можно использовать набор символов [^] (если, конечно, вы не имеете в виду старую версию IE), он будет соответствовать любому символу, включая символы новой строки.

Например:

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

где *? не жадный захват 0 или более вхождений [^].

Майкл Грант
источник
1
Для тех, кто интересуется, что [^]означает: это похоже на двойное отрицание: «соответствовать любому символу, которого нет в этом пустом списке», и поэтому все сводится к высказыванию «соответствует любому символу» .
Trincot
8

Модификатор dotall фактически превратил его в JavaScript в июне 2018 года, то есть 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
источник
0

Мое предложение состоит в том, что лучше разбить многострочную строку на «\ n» и объединить разбиения исходной строки и стать одной строкой и легко манипулировать.

<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
источник