Como posso expandir uma string como “1..15,16” em uma lista de números?
Pergunta
Tenho uma aplicação Perl que leva a partir de linha de comando de uma entrada como:
application --fields 1-6,8
eu sou obrigado a exibir os campos conforme solicitado pelo usuário na linha de comando.
Eu pensei de substituir '-' com '..' para que eu possa armazená-los em ordem por exemplo
.$str = "1..15,16" ;
@arr2 = ( $str ) ;
@arr = ( 1..15,16 ) ;
print "@arr\n" ;
print "@arr2\n" ;
O problema aqui é que @arr funciona bem (como deveria), mas em @ ARR2 toda a cadeia não é expandido como elementos da matriz.
Eu tentei usar sequências de escape, mas sem sorte.
Pode ser feito dessa maneira?
Solução
Se esta é a entrada do usuário, não use eval corda nele se você tiver quaisquer preocupações de segurança em tudo.
Tente usar Número :: Faixa vez:
use Number::Range;
$str = "1..15,16" ;
@arr2 = Number::Range->new( $str )->range;
print for @arr2;
Para evitar a morte em um intervalo inválido, faça:
eval { @arr2 = Number::Range->new( $str )->range; 1 } or your_error_handling
Há também Set :: IntSpan , que utiliza - em vez de ..:
use Set::IntSpan;
$str = "1-15,16";
@arr2 = Set::IntSpan->new( $str )->elements;
mas exige os intervalos estar em ordem e não-sobreposição (que foi escrito para uso em arquivos .newsrc, se alguém se lembra o que aqueles são). Ele também permite infinitas faixas (onde a string começa - número ou extremidades número -)., Que o método de elementos vai coaxar on
Outras dicas
Você está pensando @arr2 = eval($str);
Desde que você está tomando entrada e avaliar isso, você precisa ter cuidado.
Você deve provavelmente @arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)
P.S. Eu não sabia sobre o pacote de número :: Range, mas de incrível . Número :: Faixa ftw.
Eu tive o mesmo problema em lidar com a saída do Bit :: Vector :: to_Enum. Eu resolvi fazendo:
$range_string =~ s/\b(\d+)-(\d+)\b/expand_range($1,$2)/eg;
, em seguida, também no meu arquivo:
sub expand_range
{
return join(",",($_[0] .. $_[1]));
}
Assim, "1,3,5-7,9,12-15" se transforma em "1,3,5,6,7,9,12,13,14,15".
Eu tentei realmente difícil colocar que a expansão na 2ª parte do s /// então eu não precisaria de que a função extra, mas eu não poderia fazê-lo funcionar. I como este, porque enquanto Número :: Faixa iria funcionar, desta forma eu não ter que puxar em outro módulo para algo que deve ser trivial.
@arr2 = ( eval $str ) ;
Works, embora, naturalmente, você tem que ter muito cuidado com eval ().
Você pode usar eval:
$str = "1..15,16" ;
@arr2 = ( eval $str ) ;
@arr = ( 1..15,16 ) ;
print "@arr\n" ;
print "@arr2\n" ;
Apesar de se isto é a entrada do usuário, você provavelmente vai querer fazer alguma validação sobre a cadeia de entrada em primeiro lugar, para se certificar de que eles não têm entrada desonesto nada.
Use dividido:
@parts = split(/\,/, $fields);
print $parts[0];
1-6
print $parts[1];
8
Você não pode simplesmente colocar uma string contendo '' em uma matriz, e esperar que ele vire a elementos (exceto se você usar alguma magia negra Perl, mas não vamos entrar em detalhes aqui)
Mas Regex e divisão são seus amigos.