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

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

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

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

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

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

4 ответа

Решение

Вы ищете /.../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

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

[\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 или более вхождений [^].

Модификатор 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'

Фактически, модификатор dotall, который заставляет точку соответствовать символам новой строки, теперь находится на стадии 4 процесса TC39, что означает, что он готов к реализации.

Вы можете посмотреть на предложение здесь, это просто дополнение s флаг.
Использование в значительной степени похоже на это:

/foo.bar/s.test('foo\nbar');
// → true

и API высокого уровня:

const re = /foo.bar/s; // Or, `const re = new RegExp('foo.bar', 's');`.
re.test('foo\nbar');
// → true
re.dotAll
// → true
re.flags
// → 's'

Как написано в документах, оно реализовано в V8 из chrome 62 и в: Создайте будущее Интернета с помощью современного JavaScript (Google I/O '18), говорят, что оно уже реализовано в Chrome, Opera, Safari и NodeJS. Babel также может использовать его для браузеров, которые его не поддерживают.
Эту функцию также можно увидеть в черновиках документов TC39.

Мое предложение состоит в том, что лучше разделить многострочную строку с помощью "\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" );
        }
      }
    }

  });
});
Другие вопросы по тегам