从用户输入获取数组

时间:2012-09-25 07:33:07

标签: perl parsing eval

一个简短的问题:我希望为我的脚本用户提供输入任意数组的可能性,例如: "[1 .. 5]""[1, 2, 6, 9 .. 20]"。目前,我只是eval给定的字符串(显然不是很安全!)而perlcritic给了我5级警告。

我目前的代码:

my $arr = eval $patternData{"arr"};
unless ($arr) {
     # fixes <arr> values like "(1 .. 5)"
     $arr  = undef;
     @$arr = eval $patternData{"arr"};
}
编辑:很多人都在问:这是一个“越多越好”的东西。我搜索一个既强大(在表达方面)又简单(在调试,解析和写入输入方面)的解决方案。另外:它必须支持范围(应该容易输入超过100个条目的数组)

和 - 一如既往 - 我忘了包含我的版本。 5.8是必须的,我正在使用vSphere API,这需要5.8(我非常想念~~!)

This is perl, v5.8.8 built for MSWin32-x86-multi-thread
(with 50 registered patches, see perl -V for more detail)

Copyright 1987-2006, Larry Wall

Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com
Built Jan 23 2007 15:57:46

2 个答案:

答案 0 :(得分:4)

您对当前的输入格式有多大关系?

一个问题可能是将格式“更改”为JSON并使用JSON :: XS反序列化您的输入。 [1, 2, 3, 4]仍然是有效输入,但这不允许[1, 2, 3, 4, 8 .. 10 ]

在所有情况下,您当然需要验证输入数据是否具有正确的结构。

答案 1 :(得分:2)

如果您的数组只允许数字,我会选择这种模式(易于解析):

[1, 2, 3, 4]

我进一步假设不会有嵌套数组,例如[1, [2, 3]]或尾随逗号[1,]

然后我们只删除数组分隔符

my $line = <STDIN>;
$line =~ s/ ^\s*\[ | \]\s*$ //gx;

并将数组拆分为Perl数组。我们可以通过split

执行此操作
my @array = split /,\s*/, $line;

或通过提取所有数字

my @array = ($line =~ /(\d+)(?:,\s*|$)/g);

split解决方案还允许包含字符串,例如[1, two, 3],而第二种解决方案更严格(因此可能更安全)。

在第二步中,您可以解析范围,例如通过

@array = map {
   ($_ =~ /^(-?[\d.]+)\s*\.\.\s*(-?[\d.]+)/)
   ? ($1 .. $2)
   : $_
} @array;

如果您的数据结构变得更复杂(递归,引用),我强烈建议您使用Regexp::Grammars编写解析器。这使您可以轻松地解析递归结构以及几乎任何其他结构。