Багаторядковий прапор 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-аналізатор, відповідно. ДОМ. Це також набагато простіше.
Svante

Ви шукаєте DOTALL, а не багаторядковий.
Вануан

Зверніть увагу , що 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прапором).
alex

1
Ця відповідь була додана до поширених запитань щодо регулярного вираження стека в розділі "Модифікатори".
aliteralmind

40
За інформацією MDN, [^]також працює у відповідності з будь-якими символами, включаючи нові рядки, у JavaScript. Дивіться developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Ден Аллен

6
Для проблем з продуктивністю настійно рекомендується використовувати *?квантор замість *того, щоб уникнути жадібності. Це дозволить уникнути лову останнього <h1> документа: це, мабуть, не те, що ви хочете, і це не ефективно, оскільки регулярний вигляд продовжуватиме шукати <h1> до кінця рядка, навіть якщо він його вже знайшов раніше.
KrisWebDev

9
Версія [^] набагато простіша у компіляторі regexp, а також більш короткою.
Ерік Коррі

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
Для тих, хто задається питанням, що [^]означає: це як подвійне заперечення: "співставити будь-якого персонажа, якого немає в цьому порожньому списку", і так зводиться до слова "відповідати будь-якому символу" .
трінкот


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.