web-dev-qa-db-fra.com

Le moyen le plus efficace de vérifier si $ string commence par $ needle in perl

Étant donné deux variables de chaîne $string Et $needle Dans Perl, quelle est la façon la plus efficace de vérifier si $string Commence par $needle.

  • $string =~ /^\Q$needle\E/ Est la correspondance la plus proche à laquelle je pouvais penser qui fait ce qui est requis mais est la moins efficace (de loin) des solutions que j'ai essayées.
  • index($string, $needle) == 0 fonctionne et est relativement efficace pour certaines valeurs de $string et $needle mais recherche inutilement l'aiguille dans d'autres positions (si elle n'est pas trouvée au début).
  • substr($string, 0, length($needle)) eq $needle devrait être assez simple et efficace, mais dans la plupart de mes quelques tests n'est pas plus efficace que le précédent.

Y a-t-il une manière canonique de le faire dans Perl dont je ne serais pas au courant ou aucune manière d'optimiser l'une des solutions ci-dessus?

(dans mon cas d'utilisation particulier, $string et $needle vont être différents à chaque exécution, donc la précompilation d'une expression rationnelle n'est pas une option).


Exemple de mesure des performances d'une solution donnée (ici à partir d'un POSIX sh):

string='somewhat not so longish string' needle='somew'
time Perl -e '
  ($n,$string,$needle) = @ARGV;
  for ($i=0;$i<$n;$i++) {

    index($string, $needle) == 0

  }' 10000000 "$string" "$needle"

Avec ces valeurs, index() fonctionne mieux que substr()+eq avec ce système avec Perl 5.14.2, mais avec:

string="aaaaabaaaaabaaaaabaaaaabaaaaabaaaaab" needle="aaaaaa"

C'est inversé.

22
Stephane Chazelas

Une autre option consiste à utiliser rindex avec une position définie sur 0, ce qui signifie "obtenir l'index de $ substr dans $ str à partir de la position <= 0", c'est-à-dire qu'il vérifie simplement si $ substr est un préfixe de $ str:

> rindex "abc", "a", 0
0
> rindex "abc", "b", 0
-1
5
Gregory Kalabin

Est-ce vraiment important? J'ai fait un certain nombre de benchmarks, et la méthode index a fait en moyenne 0,68 microsecondes par itération; la méthode regex 1,14 μs; la méthode substr 0,16 μs. Même dans mes pires scénarios (chaînes de 2 250 caractères égales), index a pris 2,4 μs, regex a pris 5,7 μs et substr a pris 0,5 μs.

Mon conseil est d'écrire une routine de bibliothèque:

sub begins_with
{
    return substr($_[0], 0, length($_[1])) eq $_[1];
}

et concentrez vos efforts d'optimisation ailleurs.

MISE À JOUR: Sur la base de la critique de mon "pire cas" décrit ci-dessus, j'ai exécuté un nouvel ensemble de tests de référence avec une chaîne générée aléatoirement de 20 000 caractères, en la comparant à elle-même et à une chaîne qui ne différait que dans le dernier octet.

Pour des chaînes aussi longues, la solution d'expression régulière était de loin la pire (une expression régulière de 20 000 caractères est un enfer): 105 μs pour le succès du match, 100 μs pour l'échec du match.

Les solutions index et substr étaient encore assez rapides. index était de 11,83 μs/11,86 μs pour le succès/l'échec, et substr était de 4,09 μs/4,15 μs. Le déplacement du code vers une fonction distincte a ajouté environ 0,222 ± 0,05 μs.

Code de référence disponible sur: http://codepaste.net/2k1y8e

Je ne connais pas les caractéristiques des données de @ Stephane, mais mes conseils sont valables.

19
Sue D. Nymme