Capturer un retour à la ligne en JavaScript

Posé ici le mardi 11 août 2009 à 13:52 par Jay Salvat

RegExp sous Javascript

Pour les besoins du nouveau moteur de markItUp! 2.0, je remets le nez dans les expressions régulières. Le moteur d'expressions de Javascript est bien plus basique que celui de certains autres langages et pose des pièges sournois. Je ne sais pas si beaucoup de monde se frotte aux RegExps sous Javascript. Je partage tout de même ici une astuce qui évitera une heure de crise de nerf aux non experts de mon type.

Prenons une simple chaîne de caractères avec tags. Je veux capturer ce qui se trouve entre les deux tags.

var string  = "dehors <tag>dedans</tag> dehors";

Ici pas besoin d'être expert, l'expression basique /<tag>(.*?)<\/tag>/g fait son office.

Expression régulière avec capture simple
var string = "dehors <tag>dedans</tag> dehors";
var regex  = /<tag>(.*?)<\/tag>/g;

console.log( regex.exec(string) ); // Console Firebug

Et retourne bien ce que l'on désire.

["<tag>dedans</tag>", "dedans"]

Pourtant si la chaîne de caractère contient un retour à la ligne, cas fréquent, c'est le drame.

var string = "dehors <tag>dedans \n dedans</tag> dehors";

L'expression retourne inlassablement NULL.

Snippet

Mode Littéral

Ce qu'on ne devine pas forcement c'est que le caractère . ne capture pas les retours à la ligne. Pour capturer tous les caractères, caractères spéciaux inclus, il faut utiliser les classes de caractères \s et \S. [\s\S] capturera enfin "tous les caractères qui sont soit un espace... soit pas un espace..." (sic).

Expression régulière avec capture de retour à la ligne
var string = "dehors <tag>dedans \n dedans</tag> dehors";
var regex  = /<tag>([\s\S]*?)<\/tag>/g;

console.log( regex.exec(string) ); // Console Firebug

Maintenant ([\s\S]*?) retourne bien ce que l'on désire.

["<tag>dedans \n dedans</tag>", "dedans \n dedans"]

Mode Constructeur

La forme littérale de type /(.*)/g, bien plus élégante, ne permet pas de construire ses expressions dynamiquement et d'y inclure des variables. Il faut parfois passer par la forme avec Constructeur de type type new RegExp("(.*)", "g"). Dans ce cas, la syntaxe des classes de caractères s'échappe. La syntaxe [\s\S] deviendra [\\s\\S].

var string = "dehors <tag>dedans \n dedans</tag> dehors";
var before = "<tag>", after = "</tags>";
var regex  = new RegExp (before + "([\\s\\S]*?)" + after, "g");

console.log( regex.exec(string) ); // Console Firebug

Trackbacks

0 trackback

Commentaires

2 commentaires

Les expressions régulières en JavaScript ne sont pas géniales effectivement.
La librairie Xregexp.com pourra certainement te venir en aide dans la réécriture de markitUp!

Autrement, voici une petite regexp pour la capture des tags et de leurs contenus :

var string = "dehors <tag style='color: red' title='foo'>dedans\ndedans</tag> dehors";
var regex = /<(\w+)((?:\s+\w+(?:\s*=\s*(?:"[\s\S]*?"|'[\s\S]*?'|[^'">\s]+))?)+\s*|\s*)>([\s\S]*?)<\/\1>/g
console.log(regex.exec(string));

Ce qui nous donne :

["<tag style='color: red' title='foo'>dedans\ndedans</tag>", "tag", " style='color: red' title='foo'", "dedans\ndedans"]

Elle réalise la capture du tag, de ses attributs (sur lesquels un autre traitement pourra être effectué) et le contenu.

Je me suis inspiré du travail de Phil Haack Haacked.com/arc…omatchhtml.aspx

1. Par PiouPiouM le mercredi 12 août 2009 à 00:13

Bonjour PiouPiouM,

Je ne peux malheureusement pas trop rendre markItUp! dépendant de librairie extérieure. Déjà jQuery c'est beaucoup.

Pour la capture des tags, la difficulté que j'ai eu c'est de capturer des tags imbriqués. Javascript une fois de plus ne le permet pas. Il a fallut ruser.

Ce dont j'avais besoin :
<img src="{EDIT}source{/EDIT}" {EDIT}title="{EDIT}name{/EDIT}"{/EDIT} />

Sujet d'un prochain article. :)

2. Par Jay Salvat le mercredi 12 août 2009 à 10:16

Obligatoire. Vrai nom apprécié.

Il ne sera ni affiché, ni spammé.

Votre blog ou votre site web.

Constructif, courtois et correctement écrit. SMS proscrit. Merci.