如何将“1..15,16”这样的字符串展开为数字列表?

问题描述:

我有一个Perl的应用程序,从命令行接受一个输入为:如何将“1..15,16”这样的字符串展开为数字列表?

application --fields 1-6,8 

我需要通过命令行上的用户请求显示的字段。

我想用'..'替换'..',以便我可以将它们存储在数组中,例如

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

这里的问题是,@arr工作正常(因为它应该),但在@ ARR2整个字符串不扩大为数组元素。

我试过使用转义序列,但没有运气。

可以这样做吗?

如果这是用户输入,如果您有任何安全问题,请不要对其使用字符串评估。

尝试使用Number::Range代替:

use Number::Range; 

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

为了避免死在了无效的范围,这样做:

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

还有Set::IntSpan,它使用 - 而不是..:

use Set::IntSpan; 

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

但它需要的范围是有序和不重叠(它被编写用于.newsrc文件,如果有人记得那些是什么)。它也允许无限范围(其中字符串开始 - 数字或结束数字 - ),元素方法将咆哮。

+4

+1。 “做得对”总是比eval更好。副作用少得多。 – jrockway 2009-06-19 08:19:02

用途分:

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

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

你不能只是把包含字符串“”在数组中,并期望它转向元素(除非你使用一些Perl的黑魔法,但我们赢了这里没有进入)

但正则表达式和分裂是你的朋友。

+0

我明白...
实际上我想要的是@parts应该包含(1,2,3,4,5,6,8)
这相当于(1..6,8 ) – sud03r 2009-06-19 07:39:34

@arr2 = (eval $str) ; 

工程,虽然你必须非常小心eval()。

+0

thanx ...我只需要 – sud03r 2009-06-19 07:41:44

你可以使用eval:

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

虽然如果这是用户输入的,你可能会想要做输入字符串一些验证第一,以确保他们没有任何输入狡猾。

您正在考虑@arr2 = eval($str); 由于您正在进行输入和评估,所以您需要小心。 您应该可能@arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)

P.S.我不知道Number :: Range包,但它是awesome。数量::范围ftw。

我在处理Bit :: Vector :: to_Enum的输出时遇到了同样的问题。我解决了它这样做:

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

然后还我的文件:

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

所以 “1,3,5-7,9,12-15” 变成“1,3,5 ,6,7,9,12,13,14,15" 。

我非常努力地将扩展放在s ///的第二部分,所以我不需要额外的功能,但是我无法让它工作。我喜欢这个,因为虽然Number :: Range可以工作,但这样我就不必为另一个模块插入其他模块了。