Manipulation de chaînes

© Christian PAULUS. Document créé le 1er mai 2005 , mis à jour le 8 juillet 2007.

On n'est jamais heureux que dans le bonheur qu'on donne. Donner, c'est recevoir. Abbé Pierre

Accueil du site > Astuces > PHP > Manipulation de chaînes

Benchmark / PHP 4.3.0

La complexité des expressions régulières (REGEX) en rebute plus d’un. Il est pourtant bien utile de les maîtriser. Nous allons en voir l’exemple ici.

Objectif : comparer une fonction simple REGEX et une boucle de manipulation (retrait des caractères blancs répétitifs et autres espaces) dans une longue chaîne de caractères.

Pour cet exemple, prenons le fichier bookmark.html qui a déjà contribué au comparatif de chargement de fichiers. Ce fichier dans cet exemple, est proche du méga-octet. Cela va permettre de tester les performances de manipulations de chaînes sur des fichiers de taille respectable.

Pour plus de clarté, voici les deux fonctions créées qui sont censées donner le même résultat : retirer de cette longue chaîne de caractères les retour-chariots (\r), new-line (\n) (le premier précède souvent le suivant dans le monde windows), remplacer la tabulation par un espace blanc, et pour finir, supprimer tous les duplicatas du caractère espace.

En REGEX, ca nous donne quelque chose du genre :

<?php
    
function kzo_ereg_cleaner ($string) {
        return (
ereg_replace (" {2,}"
            
" "
            
ereg_replace ("\t"
                
" "
                
ereg_replace ("\r|\n"""$string)
                )
            )
        );
    }
?>

Dans une boucle PHP plus traditionnelle, cela donne :

<?php
    
function kzo_loop_cleaner ($string) {
        
$maxii strlen ($string);
        
$previous "";
        
$result "";
        for (
$ii 0$ii $maxii$ii++) {
            
$current $string[$ii];
            if ((
$current == "\t")) $current " ";
            if (
                    ((
$current == "\r") || ($current == "\n")) 
                || ((
$current == $previous) && ($current == " "))
                ) continue;
            
$result .= ($previous $current);
        }
        return (
$result);
    }
?>

Il est possible d’optimiser la qualité du code, notamment pour le REGEX donné en exemple, mais il est parfois étrange de constater une baisse de performance dans certains cas. Nous y reviendrons un jour s’il reste du temps à consacrer à cette particularité.

Maintenant, testons les deux fonctions par - pour une chaîne de caractères - un appel du style :

<?php
    $time_start 
getmicrotime();
    
$buffer kzo_loop_cleaner ($buffer);
    print (
"BUFFER SIZE: ".strlen ($buffer)." in ".(getmicrotime() - $time_start)." sec.<br />\n");

    
$time_start getmicrotime();
    
$buffer kzo_ereg_cleaner ($buffer);
    print (
"BUFFER SIZE: ".strlen ($buffer)." in ".(getmicrotime() - $time_start)." sec.<br />\n");
?>

Et pour les tableaux, une petite boucle qui effectue le même travail, ou presque :

<?php
    $time_start 
getmicrotime();
    for (
$ii 0$len 0$maxii count ($buffer), $buffer ""$ii $maxii$ii++) {
        
$buffer[$ii] = kzo_loop_cleaner ($buffer[$ii]);
        
$len += strlen ($buffer[$ii]);
    }
    print (
$len." c. in ".(getmicrotime() - $time_start)." sec.<br />\n");
    
    
$time_start getmicrotime();
    for (
$ii 0$len 0$maxii count ($buffer), $buffer ""$ii $maxii$ii++) {
        
$buffer[$ii] = kzo_ereg_cleaner ($buffer[$ii]);
        
$len += strlen ($buffer[$ii]);
    }
    print (
$len." c. in ".(getmicrotime() - $time_start)." sec.<br />\n");
?>

Les résultats des opérations (moyenne sur trois affichages successifs) sur une chaîne de caractères, fichier de presque 1 méga-octet :

- Par appel ereg_replace () (REGEX) : > 30 sec. ;
- Par une boucle for () sur la chaîne : 18 sec.

Les résultats des opérations (moyenne sur trois affichages successifs) sur un tableau (3000 éléments) de chaînes de caractères, fichier de presque 1 méga-octet :

- Par appel ereg_replace () (REGEX) : 1,3 sec. ;
- Par une boucle for () sur le tableau de chaînes : 18 sec.

Pour manipuler du texte dans une petite chaîne de caractères, c’est donc REGEX qui est plus performant qu’une boucle classique. Ici, les écarts sont tellement importants qu’il est impossible de rivaliser même en optimisant le code.

Par contre, sur une très grande chaîne, REGEX devient bien plus lent qu’une boucle classique. Il lui arrive même dépasser le time-out donné en standard.

Plussoyez !

Les forums sont fermés.