Comparaisons par caractères génériques (wildcard)

On connait tous les expressions rationnelles (ou regular expressions en Anglais) parce qu'elles nous on fait souffrir pendant notre enfance, et que ce n'est que grâce à des années de développement que l'on peut enfin les regarder droit dans les caractères sans détourner le regard. Mais comment passer ce savoir chèrement acquis à des utilisateurs qui n'ont pas de certification PHP, et qui pourtant aimerait bien avoir un peu plus de contrôle sur leur recherche ? Plus accessible et étonnamment familière, la solution a toujours été proche : les caractères génériques, aussi connus sous le nom de wildcards dans le farwest.

Mais c'est quoi un caractère générique ?

Dans la vie de tous les jours (si si), les caractères génériques constituent un moyen commode de désigner plusieurs noms de fichiers ou de répertoires par un seul nom. Les deux caractères génériques les plus utiles sont * et ?. Le * peut remplacer n’importe quelle séquence (chaîne) de caractères (incluant l’absence de caractères), tandis que le ? peut remplacer tout caractère unique.

Non moins utile, mais déjà plus complexes, les crochets [] permettent de définir les caractères – ou l'intervalle de caractères – à remplacer. Par exemple, [aeiouy] remplacera les voyelles, tant dis que [A-Z] remplacera les caractères de A à Z.

Ainsi, lorsque l'on fait une recherche sous Windows, Linux ou AmigaOS (je sais, je suis un passionné) pour trouver tous les fichiers ZIP, il suffit de saisir *.zip dans la zone de recherche. Si l'on cherche toutes les chansons du groupe ABBA on pourra saisir *abba*.mp3, ou même *[ab]*.mp3 (même si c'est un peu tiré par les cheveux là).

C'est quand même plus simple que /^.*abba.*\.mp3$/ non ?

Des caractères génériques à l'expression rationnelle

L'ennui, c'est que les caractères génériques, ben on dirait qu'on s'en fou en PHP. Il n'y a aucun support pour ce truc tout simple parce que le dieu preg_match() règne en maitre, et même si on le comprends parce qu'il est superbe, on aimerait bien utiliser quelque chose de plus simple.

Même si les exemples de Wildcard matching semblent assez simples, j'avais plutôt envie d'utiliser le système des expressions rationnelles de PHP, du coup j'ai crée un traducteur.

Je vous propose la fonction wd_wildcard_to_preg(), qui pourrait tenir sur une seule ligne, mais ce serait moche :

<?php

function wd_wildcard_to_preg($pattern)
{
    return '/^' . str_replace(array('\*''\?''\[''\]')array('.*''.''['']+')preg_quote($pattern)) . '$/is';
}

Ça donne quoi ?

Ben ça marche pas mal :

<?php

function wd_wildcard_match($pattern$str)
{
    $pattern = wd_wildcard_to_preg($pattern);

    return preg_match($pattern$str);
}

$str = "Le matin j'écoute madonna en me douchant.";

wd_wildcard_match('*madonna*'$str);    // 1
wd_wildcard_match('*m?donna*me'$str);  // 0
wd_wildcard_match('m?donna*me*'$str);  // 0
wd_wildcard_match('*m?donna*me*'$str)// 1
wd_wildcard_match('*[admo]*'$str);     // 1

Je m'en sers principalement pour la gestion des évènements de mon framework. Par exemple, la chaine *.save me permet d'être informé de toutes les opérations de sauvegarde, quelque soit leur origine. Vous en aurez sans doute de plus passionnantes utilisations, en tout cas vous avez toues les cartes en main, qu'elles soient sauvages ou pas (… c'est un jeu de mot).

Laisser un commentaire

Pas de commentaire