Première chose, le point est un caractère spécial dans une regex qui signifie n'importe quel caractère à l'exception d'une nouvelle ligne. Pour signifier un point au sens littéral, il faut l'échapper:\. avec un antislash.
Ce qu'on appelle \b (un "word boundary" ~ limite de mot) à un sens bien particulier dans une expression régulière. Il s'agit de la limite entre un caractère appartenant à la classe de caractères \w et tout ce qui n'est pas un caractère appartenant à \w, soit:- un caractère appartenant à \W
- Le début de la chaîne
- La fin de la chaîne
À la base \w est l'équivalent de [A-Za-z0-9_] (ou quand le modificateur u est utilisé:[\pL\pN_]) donc le point (littéral) n'y figure pas. Donc si je teste la chaîne "3.6.2" avec la pattern /3\.6\b/, cette dernière va réussir puisque "6" appartient à \w et le point n'appartient pas à \w donc le word boundary \b est bien vérifié.
Conclusion pour ce que tu cherches à délimiter, le word boundary n'est tout simplement pas approprié.
La solution de repli consiste donc à définir explicitement ce qui sépare les éléments que tu cherches du reste. Donc c'est à toi d'être au clair sur ce point (et tu dois surtout bien envisager tous les cas de figures pour éviter les mauvaises surprises). C'est le plus gros du travail.
Si par exemple je décide que ce qui sépare mon élément du reste est tout ce qui n'est ni un point ni un chiffre ascii (ce qui inclus également les limites de la chaîne), je peux écrire:- En utilisant des captures
$NouvelleChaine = preg_replace('/([^0-9.]|^)\.1\.3\.6([^0-9.]|$)/', '$1a$2', $Chaine);
- En utilisant des tests avant et arrière négatifs (negative lookahead, negative lookbehind):
$NouvelleChaine = preg_replace('/(?<![0-9.])\.1\.3\.6(?![0-9.])/', 'a', $Chaine);
Une petite remarque à propos des caractères spéciaux comme le point et de leur éventuel échappement: La plupart des caractères spéciaux n'ont plus besoin d'être échappé quand ils sont à l'intérieur d'une classe de caractère (ils y perdent leur sens spécial). C'est pour ça que j'ai écrit [0-9.] et pas [0-9\.].
Il est aussi possible quand on a une pattern comportant des parties devant être prises au sens littéral, de les encadrer avec \Q et \E pour que les caractères spéciaux contenus ne soit pas interprétés :
$NouvelleChaine = preg_replace('/(?<![0-9.])\Q.1.3.6\E(?![0-9.])/', 'a', $Chaine);
Attention tout de même car ça ne marche pas avec le délimiteur. Sinon une solution plus radicale:
$NouvelleChaine = preg_replace('/(?<![0-9.])' . preg_quote('.1.3.6', '/') . '(?![0-9.])/', 'a', $Chaine);
Partager