O sinalizador multilinha JavaScript regex não funciona

265

Eu escrevi um regex para buscar a string do HTML, mas parece que o sinalizador de múltiplas linhas não funciona.

Esse é o meu padrão e quero inserir o texto na h1tag.

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

Eu criei uma string para testá-lo. Quando a cadeia contém "\ n", o resultado é sempre nulo. Se eu removi todos os "\ n" s, obtive o resultado certo, independentemente de com ou sem o /msinalizador.

O que há de errado com meu regex?

Peter Mortensen
fonte
14
Não use expressões regulares para analisar o HTML, o HTML NÃO é uma linguagem regular. Use um analisador de HTML, resp. o DOM. Isso também é muito mais simples.
Svante
Você está procurando por DOTALL, não por várias linhas.
Vanuan
Observe que em breve o JavaScript terá o dotAllmodificador para que você possa fazer /.../se seus pontos também corresponderão a novas linhas. Em julho de 2017, estava atrás de uma bandeira no Chrome.

Respostas:

609

Você está procurando o /.../smodificador, também conhecido como modificador dotall . Força o ponto .a também corresponder às novas linhas, o que não ocorre por padrão.

A má notícia é que ele não existe no JavaScript ( existe no ES2018, veja abaixo) . A boa notícia é que você pode contornar isso usando uma classe de personagem (por exemplo \s) e sua negação ( \S) juntas, assim:

[\s\S]

Portanto, no seu caso, a regex se tornaria:

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

A partir do ES2018, o JavaScript suporta o ssinalizador (dotAll); portanto, em um ambiente moderno, sua expressão regular pode ser como você o escreveu, mas com um ssinalizador no final (em vez de m; mmuda como ^e $funciona, não .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
molf
fonte
5
@simo Corresponde a qualquer caractere de espaço em branco ou não, correspondendo efetivamente a qualquer caractere. É como ., mas corresponder espaço em branco também ( \s) significa que corresponde \n(o que .não ocorre no JavaScript ou pode ser feito com a ssinalização).
alex
1
Esta resposta foi adicionada às Perguntas frequentes sobre a expressão regular de estouro de pilha , em "Modificadores".
Alreralmind
40
Segundo a MDN, [^]também funciona para corresponder a qualquer caractere, incluindo novas linhas, em JavaScript. Veja developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Dan Allen
6
Para problemas de desempenho, é altamente recomendável usar o *?quantificador em vez de *para evitar a ganância. Isso evitará pegar o último <h1> do documento: provavelmente não é o que você deseja e não é eficiente, pois o regexp continuará procurando <h1> até o final da string, mesmo que já o tenha encontrado antes.
KrisWebDev 22/08
9
A versão [^] é muito mais fácil no compilador regexp e também mais concisa.
Erik Corry
21

Você quer o smodificador (dotall), que aparentemente não existe em Javascript - você pode substituir .por [\ s \ S], como sugerido por @molf. O mmodificador (multilinha) cria ^ e $ linhas de correspondência em vez de toda a cadeia.

Greg
fonte
4
Você poderia acrescentar que modo o / s" conjuntos modificadoras SINGLELINE em oposição ao modo de várias linhas +1.
Cerebrus
Nove anos depois, o JavaScript agora possui a sbandeira (ES2018). :-)
TJ Crowder
12

[\s\S]não funcionou para mim no nodejs 6.11.3. Com base na documentação do RegExp , ele diz para usar o [^]que funciona para mim.

(O ponto, o ponto decimal) corresponde a qualquer caractere único, exceto os terminadores de linha: \ n, \ r, \ u2028 ou \ u2029.

Dentro de um conjunto de caracteres, o ponto perde seu significado especial e corresponde a um ponto literal.

Observe que o sinalizador de múltiplas linhas m não altera o comportamento do ponto. Portanto, para combinar um padrão em várias linhas, o conjunto de caracteres [^] pode ser usado (se você não quer dizer uma versão antiga do IE, é claro), ele corresponderá a qualquer caractere, incluindo novas linhas.

Por exemplo:

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

onde o *? é a captura não gananciosa de 0 ou mais ocorrências de [^].

Michael Grant
fonte
1
Para aqueles que se perguntam o que [^]significa: é como uma dupla negação: "corresponde a qualquer caractere que não esteja nesta lista vazia " e, portanto, resume-se a dizer "corresponde a qualquer caractere" .
precisa saber é
8

O modificador dotall chegou ao JavaScript em junho de 2018, ou seja, 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
fonte
0

Minha sugestão é que é melhor dividir a sequência de várias linhas com "\ n" e concatenar as divisões da sequência original e tornar-se uma única linha e fácil de manipular.

<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
fonte