Многострочный флаг регулярного выражения 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

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(многострочных) модификаторы позволяет ^ и $ спичечных линий , а не вся строка.


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'

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

  });
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.