2009-06-19 5 views
5

Ich habe eine Perl-Anwendung, die eine Eingabe wie von der Kommandozeile nimmt:Wie kann ich eine Zeichenfolge wie "1..15,16" in eine Liste von Zahlen erweitern?

application --fields 1-6,8 

Ich bin verpflichtet, um die Felder anzuzeigen, wie durch den Benutzer auf der Kommandozeile angefordert.

Ich dachte über den Ersatz von '-' mit '..', so dass ich sie in Array z.

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

Das Problem hier ist, dass @arr gut funktioniert (wie es sein sollte), aber in @ arr2 die gesamte Zeichenfolge als Array-Elemente nicht erweitert wird.

Ich habe versucht, Escape-Sequenzen, aber kein Glück.

Kann es so gemacht werden?

Antwort

26

Wenn dies eine Benutzereingabe ist, verwenden Sie keine Zeichenfolge eval, wenn Sie irgendwelche Sicherheitsbedenken haben.

Versuchen Number::Range statt mit:

use Number::Range; 

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

auf einem ungültigen Bereich Sterben zu vermeiden, tun:

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

Es gibt auch Set::IntSpan, die verwendet - statt ..:

use Set::IntSpan; 

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

aber es erfordert die Bereiche in der Reihenfolge und nicht überlappend (it wurde für den Einsatz auf .newsrc-Dateien geschrieben, wenn sich jemand daran erinnert, was diese sind). Es erlaubt auch unendliche Bereiche (wo die Zeichenfolge beginnt - Nummer oder endet Nummer -), die die Elemente Methode krächzen wird.

+4

+1. "Es richtig zu machen" ist immer besser als eval. Viele weniger Nebenwirkungen. – jrockway

+0

Ich habe Number :: Range noch nie zuvor gesehen. Ich habe das für zukünftige Verwendung abgelegt. Danke, dass du mich darauf aufmerksam gemacht hast! –

+0

Wenn Sie Benutzereingaben nehmen, wird Ihre App auf 1..1000000000 explodieren, es sei denn, Sie haben etwa 8 GB RAM. Number :: Range-> size() ist momentan nutzlos, um dies zu verhindern, da es den gesamten Bereich generiert, um die Größe herauszufinden. –

-2

Verwendung split:

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

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

Sie können nicht nur einen String setzen enthalten ‚‘ in einem Array, und erwarten, dass es Elemente drehen (außer, wenn Sie einige Perl schwarze Magie verwenden, aber wir haben gewonnen 't gehen Sie das hier ein)

Aber Regex und Split sind Ihre Freunde.

+0

das ich verstehe ...
eigentlich was ich will ist schließlich die @parts sollte enthalten (1,2,3,4,5,6,8)
was entspricht (1..6,8) – sud03r

0
@arr2 = (eval $str) ; 

Funktioniert, obwohl Sie natürlich mit eval() sehr vorsichtig sein müssen.

+0

danke ... ich brauchte nur das – sud03r

-1

könnten Sie eval:

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

Obwohl, wenn dieser Benutzer eingegeben wird, werden Sie wahrscheinlich wollen zunächst einige Validierung auf der Eingabezeichenfolge tun, um sicherzustellen, dass sie zwielichtigen nicht eingegeben nichts.

1

Sie denken an @arr2 = eval($str); Da Sie Eingang nehmen und das bewerten, müssen Sie vorsichtig sein. Sie sollten wahrscheinlich @arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)

P.S. Ich wusste nichts über das Number :: Range-Paket, aber es ist awesome. Nummer :: Bereich ftw.

1

Ich hatte das gleiche Problem im Umgang mit der Ausgabe von Bit :: Vector :: to_Enum. Ich löste es, indem Sie:

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

dann auch in meiner Datei:

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

So "1,3,5-7,9,12-15" verwandelt sich in „1,3,5 , 6,7,9,12,13,14,15 ".

Ich habe wirklich versucht, diese Erweiterung in den zweiten Teil des s /// zu setzen, also würde ich diese zusätzliche Funktion nicht brauchen, aber ich konnte es nicht zum Laufen bringen. Ich mag das, denn während Number :: Range funktionieren würde, muss ich auf diese Weise kein weiteres Modul für etwas verwenden, das trivial sein sollte.

Verwandte Themen