É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é.
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
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.