Bonjour tout le monde !

Me voilà de retour pour une nouvelle année de blogging, qu'on espère tous plus chargée que la précédente, mais connaissant ma flemme légendaire, c’est pas gagné.
Afin de ne pas passer pour un rustre, je vous souhaite quand même à tous une excellente année 2011, mais on va passer rapidement les voeux, parce que mine de rien, on a du boulot.

Aujourd'hui, cours de Regex, on va voir les assertions.

Je suppose beaucoup de monde connait déjà les Regex, et sait en faire un usage basique pour faire des recherches ou remplacements dans une chaine de caractères. Mais tout le monde ne connait pas forcément, ou ne sait pas utiliser les assertions. Nous allons donc remédier à ça ensemble.

Le besoin :

J’ai une chaine de caractères dans laquelle je veux remplacer toutes les occurrences d’une apostrophe suivie d'un caractère alphanumérique.

La première solution (dite "du noob"):

1- On fait une recherche d’une apostrophe suivie d’un caractère alphanum:

'[a-z0-9]

2- On remplace par notre valeur

Regex.Replace(texte, @"'[a-z0-9]", @"'");

3- On se rend compte qu'on a effacé le caractère suivant, et on se débrouille pour le récupérer afin de le réafficher

Regex.Replace(texte, @"'([a-z0-9])", @"'$1");

Alors ça fonctionne, oui, mais c’est tout moche. On va faire autrement

La solution qui roxxe (ou "la Lacasa's") :

1- On utilise une assertion pour trouver nos apostrophes :

'(?=[a-z0-9])

2- On fait notre remplacement

Regex.Replace(texte, @"'(?=[a-z0-9])", @"'");

Et cette fois, ça fonctionne aussi, mais en plus propre et plus performant.

La différence entre les 2 solutions :

Dans le premier cas, notre pattern comprend une apostrophe, et le caractère se trouvant après. Si on fait un remplacement, le pattern a récupéré 2 caractères et les remplace tous les deux ; ce qui nous oblige à faire une capture sur le second caractère pour pouvoir le remettre (le $1).

Dans le second cas, nous avons une assertion qui va lire le second caractère, mais n'en tient pas compte pour le motif. L'assertion qui s’écrit avec ?= permets de dire "je veux que mon apostrophe soit suivie d’un caractère alphanum, mais je ne veux QUE l’apostrophe".

Nous avons plusieurs types d'assertions :

  • Les assertions avant ou arrière (pour dire si on cherche quelque chose qui suit ou qui précède notre apostrophe)

  • Les assertions positives ou négatives (pour dire si on cherche un quelque chose qui suit, ou quelque chose qui ne doit pas être là. On utilisera par exemple une assertion négative si on veut toutes les apostrophes qui ne sont pas précédé d’un "=")

Syntaxe :

Assertion avant positive : (?=motif)
Assertion avant negative : (?!motif)
Assertion arrière positive : (?<=motif)
Assertion arrière négative : (?<!motif)

Donc si je veux les apostrophes non précédées d'un =, je ferai ça :

Regex.Replace(texte, @"(?<!=)'", @"&apos;");