2009-06-19 5 views
5

J'ai une application Perl qui prend de la ligne de commande une entrée comme:Comment puis-je développer une chaîne comme "1.15,16" dans une liste de nombres?

application --fields 1-6,8 

Je suis tenu d'afficher les champs comme demandé par l'utilisateur sur la ligne de commande. J'ai pensé à remplacer '-' par '..' afin que je puisse les stocker en réseau, par exemple.

$str = "1..15,16" ; 
@arr2 = ($str) ; 
@arr = (1..15,16) ; 
print "@arr\n" ; 
print "@arr2\n" ; 

Le problème ici est que @arr fonctionne très bien (comme il se doit), mais dans @ arr2 la chaîne entière est pas étendue comme éléments du tableau.

J'ai essayé d'utiliser des séquences d'échappement mais pas de chance.

Peut-il être fait de cette façon?

Répondre

26

S'il s'agit d'une entrée de l'utilisateur, n'utilisez pas de chaîne de caractères si vous avez des problèmes de sécurité.

Essayez d'utiliser Number::Range à la place:

use Number::Range; 

$str = "1..15,16" ; 
@arr2 = Number::Range->new($str)->range; 
print for @arr2; 

Pour éviter de mourir sur une plage non valide, faire:

eval { @arr2 = Number::Range->new($str)->range; 1 } or your_error_handling 

Il y a aussi Set::IntSpan, qui utilise - au lieu de ..:

use Set::IntSpan; 

$str = "1-15,16"; 
@arr2 = Set::IntSpan->new($str)->elements; 

mais il faut que les plages soient en ordre et ne se chevauchent pas a été écrit pour une utilisation sur les fichiers .newsrc, si quelqu'un se souvient de ce que ceux-ci sont). Il permet également des plages infinies (où la chaîne commence - numéro ou se termine numéro -), que la méthode des éléments va croasser.

+4

+1. "Faire les choses correctement" est toujours préférable à l'évaluation. Beaucoup moins d'effets secondaires. – jrockway

+0

Je n'ai jamais rencontré Number :: Range avant. J'ai classé cela pour une utilisation future. Merci de m'avoir fait prendre conscience de cela! –

+0

Si vous prenez l'entrée de l'utilisateur, votre application va exploser sur 1..1000000000, sauf si vous avez environ 8 Go de RAM. Number :: Range-> size() est inutile en ce moment pour éviter cela car il génère toute la gamme pour comprendre la taille. –

-2

utilisation fractionnée:

@parts = split(/\,/, $fields); 

print $parts[0]; 
1-6 
print $parts[1]; 
8 

Vous ne pouvez pas simplement mettre une chaîne contenant « » dans un tableau, et attendre de se tourner vers des éléments (sauf si vous utilisez un peu de magie noire Perl, mais nous avons gagné Ne pas entrer dans cela ici)

Mais Regex et split sont vos amis.

+0

que je comprends ...
effectivement ce que je veux est enfin le @parts devrait contenir (1,2,3,4,5,6,8)
ce qui est équivalent à (1..6,8) – sud03r

0
@arr2 = (eval $str) ; 

Fonctionne bien, bien sûr, vous devez être très prudent avec eval().

+0

merci ... j'avais juste besoin de ça – sud03r

-1

Vous pouvez utiliser eval:

$str = "1..15,16" ; 
@arr2 = (eval $str) ; 
@arr = (1..15,16) ; 
print "@arr\n" ; 
print "@arr2\n" ; 

Bien que si cela est entrée utilisateur, vous aurez probablement envie de faire une validation sur la chaîne d'entrée en premier lieu, pour vous assurer qu'ils ont quoi que ce soit pas entrée louches.

1

Vous songez à @arr2 = eval($str); Puisque vous prenez des commentaires et que vous évaluez cela, vous devez faire attention. Vous devriez probablement @arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)

P.S. Je ne connaissais pas le paquet Number :: Range, mais c'est awesome. Nombre :: Plage ftw.

1

J'ai eu le même problème en traitant la sortie de Bit :: Vector :: to_Enum. Je l'ai résolu en faisant:

$range_string =~ s/\b(\d+)-(\d+)\b/expand_range($1,$2)/eg; 

puis aussi dans mon dossier:

sub expand_range 
{ 
    return join(",",($_[0] .. $_[1])); 
} 

Alors "1,3,5-7,9,12-15" se transforme en « 1,3,5 6,7,9,12,13,14,15 ".

J'ai essayé vraiment de mettre cette expansion dans la 2ème partie du s ///, donc je n'aurais pas besoin de cette fonction supplémentaire, mais je n'ai pas réussi à l'obtenir. J'aime ça parce que Number :: Range fonctionne, de cette façon je n'ai pas besoin d'insérer un autre module pour quelque chose qui devrait être trivial.