JavaScript regex multiline flag no funciona

265

Escribí una expresión regular para recuperar una cadena de HTML, pero parece que la bandera multilínea no funciona.

Este es mi patrón y quiero obtener el texto en la h1etiqueta.

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

Creé una cadena para probarlo. Cuando la cadena contiene "\ n", el resultado es siempre nulo. Si eliminé todos los "\ n" s, me dio el resultado correcto, sin importar con o sin la /mbandera.

¿Qué le pasa a mi expresión regular?

Peter Mortensen
fuente
14
No use expresiones regulares para analizar HTML, HTML no es un lenguaje regular. Use un analizador HTML, resp. el DOM Eso también es mucho más simple.
Svante
Estás buscando DOTALL, no multilínea.
Vanuan
Tenga en cuenta que JavaScript pronto tendrá el dotAllmodificador para que pueda hacerlo /.../sy sus puntos también coincidirán con nuevas líneas. A partir de julio de 2017, está detrás de una bandera en Chrome.

Respuestas:

609

Está buscando el /.../smodificador, también conocido como modificador dotall . Obliga al punto .a coincidir también con las nuevas líneas, lo que no hace de manera predeterminada.

La mala noticia es que no existe en JavaScript (lo hace a partir de ES2018, ver más abajo) . La buena noticia es que puede solucionarlo utilizando una clase de caracteres (por ejemplo \s) y su negación ( \S) juntos, de esta manera:

[\s\S]

Entonces, en su caso, la expresión regular se convertiría en:

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

A partir de ES2018, JavaScript admite el sindicador (dotAll), por lo que en un entorno moderno su expresión regular podría ser como la escribió, pero con un sindicador al final (en lugar de m; mcambia cómo ^y $funciona, no .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
molf
fuente
55
@simo Coincide con cualquier carácter de espacio en blanco o sin espacio en blanco, haciendo coincidir efectivamente cualquier carácter. Es como ., pero la coincidencia de espacios en blanco también ( \s) significa que coincide \n(lo .que no funciona en JavaScript, o puede hacerse con la sbandera).
alex
1
Esta respuesta se ha agregado a las Preguntas frecuentes sobre la expresión regular de desbordamiento de pila , en "Modificadores".
aliteralmind
40
Según MDN, [^]también funciona para que coincida con cualquier carácter, incluidas las nuevas líneas, en JavaScript. Ver developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen
66
Para problemas de rendimiento, se recomienda utilizar el *?cuantificador en lugar de *evitar la codicia. Esto evitará atrapar el último <h1> del documento: eso probablemente no sea lo que desea y eso no es eficiente ya que la expresión regular continuará buscando <h1> hasta el final de la cadena, incluso si ya lo ha encontrado antes.
KrisWebDev
9
La versión [^] es mucho más fácil en el compilador regexp, y también más breve.
Erik Corry
21

Desea el smodificador (dotall), que aparentemente no existe en Javascript; puede reemplazarlo .con [\ s \ S] como lo sugiere @molf. El mmodificador (multilínea) hace que ^ y $ coincidan líneas en lugar de toda la cadena.

Greg
fuente
44
Puede agregar que el modificador / s "establece el modo de línea única en lugar del modo multilínea. +1
Cerebrus
Nueve años después, JavaScript ahora tiene la sbandera (ES2018). :-)
TJ Crowder
12

[\s\S]no funcionó para mí en nodejs 6.11.3. Basado en la documentación de RegExp , dice usar [^]lo que funciona para mí.

(El punto, el punto decimal) coincide con cualquier carácter único, excepto los terminadores de línea: \ n, \ r, \ u2028 o \ u2029.

Dentro de un conjunto de caracteres, el punto pierde su significado especial y coincide con un punto literal.

Tenga en cuenta que la bandera m multilínea no cambia el comportamiento del punto. Por lo tanto, para hacer coincidir un patrón en varias líneas, se puede usar el conjunto de caracteres [^] (si no se refiere a una versión anterior de IE, por supuesto), coincidirá con cualquier carácter, incluidas las nuevas líneas.

Por ejemplo:

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

donde el *? es la captura no codiciosa de 0 o más ocurrencias de [^].

Michael Grant
fuente
1
Para aquellos que se preguntan qué [^]significa: es como una doble negación: "coincidir con cualquier personaje que no esté en esta lista vacía ", por lo que todo se reduce a decir "coincidir con cualquier personaje" .
Trincot
8

El modificador dotall ha llegado a JavaScript en junio de 2018, es decir, 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
fuente
0

Mi sugerencia es que es mejor dividir la cadena de varias líneas con "\ n" y concatenar las divisiones de la cadena original y se convierte en una sola línea y 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
fuente