0 votes

Correspondance avec une chaîne littérale

J'ai une page web où les utilisateurs peuvent ajouter des smileys à leurs commentaires. Et je veux limiter le nombre de smileys par commentaire. Le "système" fonctionne mais j'ai quelques problèmes avec la partie regex. J'ai défini mes smileys dans un fichier de configuration comme suit :

$config['Smilies'] = Array (
    // irrelevant stuff
    'smilies' => Array (
        ':)' => 'smile.gif',
        ':(' => 'sad.gif',
        // some more smilies
        's:10' => 'worship.gif',
        's:11' => 'zip.gif',
        's:12' => 'heart.gif',
        // some more smilies
        's:1' => 'dry.gif',
        's:2' => 'lol.gif',
        's:3' => 'lollol.gif',
        // some more smilies
    )
);

Ensuite, lorsque je valide le commentaire (pour voir combien de smileys il y a), je passe en boucle par ce tableau et je fais correspondre le smiley au contenu du commentaire. La regex est utilisée comme suit :

foreach ( $this->config['smilies'] as $smilie => $smilieImage )
{
    $matches = Array ();
    Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '/i', $Content, $matches );

    $numOfFoundSmilies += Count ( $matches[0] );
}

Le problème est le suivant que si je saisis "s:10" dans le commentaire, le code ci-dessus trouvera deux correspondances : "s:10" et "s:1". Mes connaissances en matière d'expressions régulières sont très faibles, et je n'arrive pas à résoudre ce problème.

4voto

Victor Nicollet Points 16924

Votre code compte, pour chaque code de sourire, le nombre de fois que ce code apparaît dans le message, de sorte que "s:10" compte à la fois comme "s:10" et "s:1".

Une solution consisterait à rechercher tous les codes de sourire en une seule fois, de sorte que chaque élément du message ne compte que pour un seul code de sourire. Pour ce faire, il suffit de combiner tous les codes dans une seule expression rationnelle.

$codes = array_keys($smilie);
$escCodes = array_map('preg_quote', $codes);
$regex = '/'.implode('|',$escCodes).'/i';

preg_match_all($regex, $Content, $matches);

$found = count($matches);

3voto

Boldewyn Points 29961

Les expressions régulières sont avide par défaut (au moins pour les PCRE). En général, il est possible de contourner ce problème :

/a+/ # selects the whiole string from "aaaaaaa"

/a+?/ # selects only "a"

Dans votre cas, cela ne sert pas à grand-chose, car vous ne pouvez pas simplement ajouter un point d'interrogation quelque part. La seule possibilité est de réorganiser votre tableau de recherche et instantanément remplacer les lieux trouvés. Recherche premier pour s:10 y deuxième pour s:1 et utiliser preg_replace() au lieu de la correspondance. De cette manière, le second ne trouve plus le premier.

Autre possibilité : Divisez votre tableau de recherche en deux. Si vous savez que l'un d'eux a toujours la structure 's:' plus des chiffres, vous pouvez utiliser votre expression rationnelle dans cette deuxième boucle comme suit

Preg_Match_All ( '/' . Preg_Quote ( $smilie ) . '(?![0-9])/i', $Content, $matches );

avec (?![0-9]) a expression du regard vers l'avenir à la recherche de tout non -chiffre.

Et un troisième : Si vous n'autorisez (== convertissez) les smileys qu'à certains endroits, vous pouvez utiliser ceci :

Preg_Match_All ( '/\b' . Preg_Quote ( $smilie ) . '\b/i', $Content, $matches );

\b est une "limite de mot", généralement n'importe quel "not-" (lettre, chiffre, trait de soulignement). L'inconvénient est évidemment que tous les smileys (comme "abc;-)xyz") ne seront pas trouvés.

1voto

Gordon Points 156415

J'imagine que ce code est plus rapide qu'une Regex

$replaced = str_replace(array_keys($config['Smilies']), 
                        array_values($config['Smilies']),
                        $message, $count);

Cela ne résoudrait pas les problèmes liés aux s:1 y s:10 Cependant, je suggérerais d'utiliser un délimiteur/une notation de frontière plus claire, par exemple :s10: au lieu de s:10 . Il n'y aura alors plus de problème.

En outre, je suggère de ne pas utiliser d'identificateurs numériques dans ce cas. Les utilisateurs trouveront probablement fastidieux de s'en souvenir. Pourquoi ne pas utiliser des étiquettes faciles à mémoriser, par exemple :heart: o :lol: ?

0voto

Residuum Points 6345

Vous pouvez modifier votre regexen pour utiliser limites des mots o \s (espacement) à faire correspondre, de sorte que s:1 devient \bs:1\b o \ss:1\s . Attention, avec la deuxième méthode s:1. ne sera pas pris en compte, et les deux versions ne seront pas prises en compte. This is my funny texts:1 .

0voto

Dave Child Points 1789

Remplacer "s:1" par "s:1[^0-9]" - qui correspond à tout "s:1" non suivi d'un autre nombre.

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