web-dev-qa-db-fra.com

Le drapeau multiligne regex JavaScript ne fonctionne pas

J'ai écrit une expression rationnelle pour extraire une chaîne à partir de HTML, mais il semble que l'indicateur multiligne ne fonctionne pas.

Ceci est mon modèle et je veux obtenir le texte en h1 tag.

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 je supprimais tous les "\ n" s, cela me donnait le bon résultat, que ce soit avec ou sans le /m drapeau.

Quel est le problème avec mon regex?

252
wangyh

Vous recherchez le modificateur /.../s, É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 que n'existe pas en JavaScript (à partir de 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 suit:

[\s\S]

Donc, dans votre cas, la regex deviendrait:

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

À compter de ES2018, JavaScript prend en charge le drapeau s (dotAll). Ainsi, dans un environnement moderne, votre expression régulière pourrait être comme vous l'avez écrite, mais avec un drapeau s à la fin (plutôt que m; m modifie le fonctionnement de ^ et $ et non de .):

/<div class="box-content-5">.*<h1>([^<]+?)<\/h1>/is
590
molf

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

20
Greg

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

(Le point, le point décimal) correspond à n'importe quel caractère, à l'exception des caractères de fin 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 multiligne m ne modifie pas le comportement du point. Donc, pour faire correspondre un motif 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 fera correspondre tout caractère, y compris les nouvelles lignes.

Par exemple:

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

où le *? est le grab non gourmand de 0 ou plus occurrences de [^].

12
Michael Grant

Le modificateur dotall a en fait intégré 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'
7
Forivin