304 votes

Comment utiliser l'expression rationnelle JavaScript sur plusieurs lignes ?

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre.*?<\/pre>/gm );
alert(arr);     // null

Je voudrais que le bloc PRE soit repris, même s'il s'étend sur plusieurs caractères de saut de ligne. Je pensais que le drapeau 'm' le faisait. Ce n'est pas le cas.

J'ai trouvé la réponse aquí avant de poster. Puisque je pensais connaître JavaScript (j'ai lu trois livres, travaillé des heures) et qu'il n'y avait pas de solution existante chez SO, je vais oser poster quand même. jeter des pierres ici

La solution est donc la suivante :

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[\s\S]*?<\/pre>/gm );
alert(arr);     // <pre>...</pre> :)

Quelqu'un a-t-il une façon moins cryptique de le faire ?

Edit : ce est un doublon mais comme il est plus difficile à trouver que le mien, je ne le supprime pas.

Elle propose [^] comme un "point multiligne". Ce que je ne comprends toujours pas, c'est pourquoi [.\n] ne fonctionne pas. Je suppose que c'est l'une des parties tristes de JavaScript

36 votes

Une regex moins cryptique ? Impossible, par nature.

0 votes

Au fait, vous devriez lire : "Parsing Html : La méthode Cthulhu" codinghorror.com/blog/archives/001311.html

2 votes

Le lien a changé par rapport au commentaire précédent : blog.codinghorror.com/parsing-html-the-cthulhu-way (environ 5 ans plus tard)

352voto

KrisWebDev Points 1788

N'utilisez pas (.|[\r\n]) au lieu de . pour une correspondance multiligne.

UTILISER [\s\S] au lieu de . pour la correspondance entre plusieurs lignes

De même, évitez la gourmandise là où elle n'est pas nécessaire en utilisant *? o +? au lieu du quantificateur * o + . Cela peut avoir un impact considérable sur les performances.

Voir le repère que j'ai fait : http://jsperf.com/javascript-multiline-regexp-workarounds

Using [^]: fastest
Using [\s\S]: 0.83% slower
Using (.|\r|\n): 96% slower
Using (.|[\r\n]): 96% slower

NB : Vous pouvez également utiliser [^] mais il est déprécié dans le commentaire ci-dessous.

26 votes

Bons points, mais je recommande de ne pas utiliser [^] de toute façon. D'une part, JavaScript est la seule saveur que je connaisse qui supporte cet idiome, et même là, il est utilisé loin d'être aussi souvent que [\s\S] . D'autre part, la plupart des autres saveurs vous permettent d'échapper à la ] en le listant en premier. En d'autres termes, en JavaScript [^][^] correspond à deux caractères quelconques, mais en .NET, il correspond à n'importe quel caractère. un caractère autre que ] , [ ou ^ .

2 votes

Comment savez-vous que \S correspondra à \r o \n par rapport à un autre personnage ?

7 votes

Voir cette question pour \s\S détails. Il s'agit d'un hack permettant de faire correspondre tous les caractères d'espace blanc + tous les caractères sans espace blanc = tous les caractères. Voir aussi MDN pour la documentation des caractères spéciaux de regexp.

277voto

Brian Campbell Points 101107

[.\n] ne fonctionne pas car . n'a pas de signification particulière à l'intérieur de [] ça veut dire que c'est juste un littéral . . (.|\n) serait un moyen de spécifier "tout caractère, y compris une nouvelle ligne". Si vous voulez faire correspondre tous les retours à la ligne, vous devriez ajouter \r ainsi que pour inclure les fins de ligne de style Windows et Mac OS classique : (.|[\r\n]) .

Cela s'avère être un peu lourd, ainsi que lent, (voir La réponse de KrisWebDev pour plus de détails ). Une meilleure approche consisterait donc à faire correspondre tous les caractères d'espacement et tous les caractères autres que d'espacement, en utilisant la commande [\s\S] qui correspondra à tout, et qui est plus rapide et plus simple.

En général, vous ne devriez pas essayer d'utiliser une regexp pour faire correspondre les balises HTML réelles. Voir, par exemple, ces questions pour en savoir plus.

Au lieu de cela, essayez de rechercher dans le DOM la balise dont vous avez besoin (l'utilisation de jQuery rend cette opération plus facile, mais vous pouvez toujours faire ce qui suit document.getElementsByTagName("pre") avec le DOM standard), puis recherchez le contenu textuel de ces résultats avec une regexp si vous avez besoin d'une correspondance avec le contenu.

0 votes

Je suis en train de faire une conversion .wiki -> HTML à la volée, en utilisant JavaScript. Par conséquent, je n'ai pas encore le DOM disponible. Le fichier wiki est principalement constitué de sa propre syntaxe, mais j'autorise l'utilisation de balises HTML si nécessaire. Votre conseil est le suivant très valable, si je m'occupais de DOM avec ça. Merci. :)

0 votes

C'est vrai. Je suppose que c'est une raison valable pour vouloir utiliser les regex sur le HTML, bien que les syntaxes wiki mélangées avec le HTML peuvent avoir toutes sortes de cas de coin amusants eux-mêmes.

2 votes

[\r\n] appliqué à une séquence \r\n correspondrait d'abord à \r et ensuite \n. Si vous voulez faire correspondre la séquence entière en une seule fois, indépendamment du fait que cette séquence soit \r\n ou simplement \n utiliser le modèle .|\r?\n

34voto

Neek Points 1384

Vous ne précisez pas votre environnement et votre version de Javascript (ECMAscript), et je réalise que ce post date de 2009, mais juste pour être complet, avec la sortie de l'ECMA2018, nous pouvons maintenant utiliser la fonction s pour provoquer . pour correspondre à ' \n ', voir https://stackoverflow.com/a/36006948/141801

Ainsi :

let s = 'I am a string\nover several\nlines.';
console.log('String: "' + s + '".');

let r = /string.*several.*lines/s; // Note 's' modifier
console.log('Match? ' + r.test(s); // 'test' returns true

Il s'agit d'un ajout récent qui ne fonctionnera pas dans de nombreux environnements actuels. Par exemple, Node v8.7.0 ne semble pas le reconnaître, mais il fonctionne dans Chromium, et je l'utilise dans un test Typescript que j'écris.

12voto

Y. Shoham Points 3389

[.\n] ne fonctionne pas, car le point dans [] (par définition regex ; pas seulement javascript) signifie le caractère point. Vous pouvez utiliser (.|\n) (o (.|[\n\r]) ) à la place.

27 votes

[\s\S] est l'idiome JavaScript le plus courant pour faire correspondre tout, y compris les nouvelles lignes. C'est plus facile pour les yeux et beaucoup plus efficace qu'une approche basée sur l'alternance comme (.|\n) . (Il signifie littéralement "tout personnage qui es espace blanc ou tout caractère qui n'est pas les espaces blancs).

2 votes

Vous avez raison, mais la question portait sur . y \n et pourquoi [.\n] ne fonctionne pas. Comme mentionné dans la question, le [^] est également une bonne approche.

9voto

KhunRan Points 312

Je l'ai testé (Chrome) et cela fonctionne pour moi (à la fois [^] y [^\0] ), en changeant le point ( . ) avec soit [^\0] o [^] car le point ne correspond pas au saut de ligne (voir ici) : http://www.regular-expressions.info/dot.html ).

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[^\0]*?<\/pre>/gm );
alert(arr);     //Working

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X