1

一个简短的问题:我想让我的脚本的用户可以输入任意数组,例如"[1 .. 5]"or "[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 是必须的,我正在使用需要 5.8 的 vSphere API(我~~非常想念!)

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
4

2 回答 2

4

您与当前输入格式的关系如何?

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

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

于 2012-09-25T07:46:02.850 回答
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编写解析器。这使您可以轻松解析递归结构以及几乎任何其他内容。

于 2012-09-25T07:42:16.183 回答