2012-03-30 1 views
9

J'ai beaucoup travaillé récemment avec perl, je ne sais toujours pas comment <,>,>=,=<, ne,gt, etc .. sur les "nombres" stringifiés, par "nombre" je veux dire quelque chose comme: '1.4 .5.6.7.8.0'Perl comparer les opérateurs et les "nombres" stringifiés

-moi si je me trompe, le vrai retours suivants:

if ('1.4.5' > '8.7.8'); 

parce que les deux seront contraints à true (pas une chaîne vide). mais, comment fonctionne ne,gt, les opérateurs de chaînes etc fonctionnent sur de tels numéros?

fondamentalement, je suis en train de comparer les numéros de version se composait de la forme suivante:

1.3.4.0.2 

je peux faire une comparaison numérique de chaque chiffre, mais avant, je ranther veux savoir de la chaîne comparant les opérateurs effectuer sur de telles chaînes.

Merci,

+1

"1.4.5.6.7.8.0" est pas un nombre. Voir [perldata] (http://perldoc.perl.org/perldata.html) et [Scalar :: Util] (http://search.cpan.org/perldoc?Scalar::Util) 's looks_like_number'. – ikegami

+0

J'ai dit "numéros" – snoofkin

+1

En fait, vous avez dit "numéro": "par" nombre "Je veux dire quelque chose comme: '1.4.5.6.7.8.0'». Et puis vous avez utilisé «'> '», qui prend un * nombre * de chaque côté, donc mon commentaire est approprié même si vous avez dit «numéros». – ikegami

Répondre

17

Première: S'il vous plaît use warnings tout le temps. Vous auriez réalisé ce qui suit à la fois:

$ perl -wle 'print 1 unless "1.4.5" > "8.7.8"' 
Argument "8.7.8" isn't numeric in numeric gt (>) at -e line 1. 
Argument "1.4.5" isn't numeric in numeric gt (>) at -e line 1. 

Perl v5.9.0 est venu distribué avec version. Et ce module, il est très facile de comparer les numéros de version:

use warnings; 
use version; 

my ($small, $large) = (version->parse('1.4.5'), version->parse('8.7.8')); 

print "larger\n" if $small > $large; 
print "smaller\n" if $small < $large; 
8

Une comparaison de chaînes ne fonctionneront que si tous les nombres entre les points a la même longueur. Une comparaison de chaînes n'a aucune connaissance de numéro et commencera à comparer les points et les chiffres (car ils sont les deux caractères dans une chaîne).

Il un module CPAN qui fait exactement ce que vous cherchez: Sort::Versions

3

Lorsque vous comparez des chaînes en utilisant des opérateurs de relation numérique <, >, etc., Perl émet un avertissement si vous use warnings. Cependant, Perl tentera toujours de convertir les chaînes en nombres. Si la chaîne commence par des chiffres, Perl les utilisera, sinon la chaîne équivaut à 0. Dans votre exemple, comparer '1.4.5' et '8.7.8' a le même effet que la comparaison des nombres 1.4 et 8.7.

Mais pour ne, gt, etc. cela n'a pas vraiment d'importance si vos chaînes sont composées de nombres ou d'autres éléments (y compris des points). Par conséquent:

print "greater" if '2.3.4' gt '10.1.2' # prints 'greater' because '2' > '1' stringwise 
print "greater" if '02.3.4' gt '10.1.2' # prints nothing because '0' < '1' stringwise 

Par conséquent, vous ne pouvez pas utiliser ni >, <, etc., ni gt, lt, etc. pour la comparaison de version, vous devez choisir approche différente, comme proposé dans une autre réponse, par exemple.

2

Vous n'êtes pas sûr de l'overhead de ceci, mais vous pouvez essayer Sort::Naturally. Et en particulier, l'opérateur ncmp.

2

Comme @tent a souligné, @ solution de SebastianStumpf est proche, mais pas tout à fait raison parce que:

>perl -Mversion -e 'my @n = ("1.10", "1.9"); print "$n[0] is " . (version->parse($n[0]) > version->parse($n[1]) ? "larger" : "smaller") . " than $n[1]\n";' 
1.10 is smaller than 1.9 

Heureusement, cela est facilement résolu après la pointe dans version's documentation:

Le principal « v 'est maintenant fortement recommandé pour plus de clarté, et jettera un avertissement dans une prochaine version si omis.

>perl -Mversion -e 'my @n = ("1.10", "1.9"); print "$n[0] is " . (version->parse("v$n[0]") > version->parse("v$n[1]") ? "larger" : "smaller") . " than $n[1]\n";' 
1.10 is larger than 1.9 
Questions connexes