Le drapeau multiligne regex JavaScript ne fonctionne pas

265

J'ai écrit une expression régulière pour récupérer la chaîne de code HTML, mais il semble que l'indicateur multiligne ne fonctionne pas.

Ceci est mon modèle et je veux obtenir le texte dans la h1balise.

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

J'ai créé une chaîne pour le tester. Lorsque la chaîne contient "\ n", le résultat est toujours nul. Si j'ai supprimé tous les "\ n", cela m'a donné le bon résultat, peu importe avec ou sans le /mdrapeau.

Quel est le problème avec mon regex?

Peter Mortensen
la source
14
N'utilisez pas d'expressions régulières pour analyser HTML, HTML n'est PAS un langage régulier. Utilisez un analyseur HTML, resp. le DOM. C'est aussi beaucoup plus simple.
Svante
Vous recherchez DOTALL, pas multiligne.
Vanuan
Notez que JavaScript aura bientôt le dotAllmodificateur pour que vous puissiez le faire /.../set vos points correspondront également à de nouvelles lignes. Depuis juillet 2017, il est derrière un drapeau dans Chrome.

Réponses:

609

Vous recherchez le /.../smodificateur, également appelé modificateur dotall . Il force le point .à correspondre également aux nouvelles lignes, ce qu'il ne fait pas par défaut.

La mauvaise nouvelle est qu'elle n'existe pas en JavaScript (elle existe depuis ES2018, voir ci-dessous) . La bonne nouvelle est que vous pouvez contourner ce problème en utilisant une classe de caractères (par exemple \s) et sa négation ( \S) ensemble, comme ceci:

[\s\S]

Donc, dans votre cas, l'expression régulière deviendrait:

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

À partir d'ES2018, JavaScript prend en charge le sdrapeau (dotAll), donc dans un environnement moderne, votre expression régulière pourrait être telle que vous l'avez écrite, mais avec un sdrapeau à la fin (plutôt que m; mchange la façon ^et le $travail, non .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
molf
la source
5
@simo Correspond à tout caractère blanc ou non blanc, correspondant effectivement à n'importe quel caractère. C'est comme ., mais faire correspondre les espaces aussi ( \s) signifie qu'il correspond \n(ce qui .ne fait pas en JavaScript, ou peut être fait avec le sdrapeau).
alex
1
Cette réponse a été ajoutée à la FAQ sur l'expression régulière de débordement de pile , sous "Modificateurs".
aliteralmind
40
Selon MDN, [^]fonctionne également pour faire correspondre n'importe quel caractère, y compris les sauts de ligne, en JavaScript. Voir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dan Allen
6
Pour les problèmes de performances, il est fortement recommandé d'utiliser le *?quantificateur au lieu de *afin d'éviter la gourmandise. Cela évitera d'attraper le dernier <h1> du document: ce n'est probablement pas ce que vous voulez et ce n'est pas efficace car l'expression régulière continuera à rechercher <h1> jusqu'à la fin de la chaîne même si elle l'a déjà trouvé auparavant.
KrisWebDev
9
La version [^] est beaucoup plus facile sur le compilateur d'expressions rationnelles, et aussi plus concise.
Erik Corry
21

Vous voulez le smodificateur (dotall), qui n'existe apparemment pas en Javascript - vous pouvez le remplacer .par [\ s \ S] comme suggéré par @molf. Le mmodificateur (multiligne) fait correspondre les lignes ^ et $ plutôt que la chaîne entière.

Greg
la source
4
Vous pouvez ajouter que le modificateur / s "définit le mode monoligne par opposition au mode multiligne. +1
Cerebrus
Neuf ans plus tard, JavaScript a maintenant le sdrapeau (ES2018). :-)
TJ Crowder
12

[\s\S]n'a pas fonctionné pour moi dans nodejs 6.11.3. Basé sur la documentation RegExp , il dit d'utiliser [^]ce qui fonctionne pour moi.

(Le point, le point décimal) correspond à n'importe quel caractère, à l'exception des terminateurs de ligne: \ n, \ r, \ u2028 ou \ u2029.

À l'intérieur d'un jeu de caractères, le point perd sa signification particulière et correspond à un point littéral.

Notez que l'indicateur m multiligne ne change pas le comportement des points. Donc, pour faire correspondre un modèle sur plusieurs lignes, le jeu de caractères [^] peut être utilisé (si vous ne voulez pas dire une ancienne version d'IE, bien sûr), il correspondra à n'importe quel caractère, y compris les nouvelles lignes.

Par exemple:

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

où le *? est la capture non gourmande de 0 ou plusieurs occurrences de [^].

Michael Grant
la source
1
Pour ceux qui se demandent ce que cela [^]signifie: c'est comme une double négation: "correspondre à n'importe quel caractère qui n'est pas dans cette liste vide " et donc cela revient à dire "correspondre à n'importe quel caractère" .
trincot
8

Le modificateur dotall est en fait devenu JavaScript en juin 2018, c'est-à-dire 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
la source
0

Ma suggestion est qu'il est préférable de diviser la chaîne de plusieurs lignes avec "\ n" et de concaténer les divisions de la chaîne d'origine et devient une seule ligne et facile à manipuler.

<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
la source