两个重要问题的答案将影响您是否需要使用正则表达式来匹配各种数字格式,或者您是否可以做一些更简单的事情:
- 您确定您的行仅包含数字还是它们还包含其他数据(或者可能某些行根本没有数字而只有其他数据)?
- 您确定所有数字之间和/或其他数据之间至少用一个空格分隔吗?如果不是,它们是如何分开的? (例如,
portsnap fetch 的输出会生成许多类似 3690....3700.... 的数字,带有小数点,根本没有用于分隔它们的空格。
如果你的行只包含数字而没有其他数据,并且数字用空格分隔,那么你甚至不需要检查结果是否为数字,而只需将行分开:
my @numbers = split /\s+/;
如果您不确定您的行是否包含数字,但您确定每个数字与其他数字或其他数据之间至少有一个空格,那么下一行代码是正确提取数字的好方法用一种巧妙的方式让 Perl 本身识别所有许多不同的合法数字格式。 (这假设您不想将其他数据值转换为NaN。)@numbers 中的结果将正确识别当前输入行中的所有数字。
my @numbers = grep { 1*$_ eq $_ } m/(\S*\d\S*)/g;
# we could do simply a split, but this is more efficient because when
# non-numeric data is present, it will only perform the number
# validation on data pieces that actually do contain at least one digit
您可以通过检查表达式@numbers > 1 的真值来确定是否存在至少一个数字,以及通过使用条件@numbers == 4 等来确定是否恰好存在四个。
如果您的数字相互碰撞,例如 5.17e+7-4.0e-1,那么您将遇到更困难的时期。这是唯一需要复杂正则表达式的时候。
注意:更新的代码更快/更好。
注意 2:由于 map 在存储 undef 的值时的工作方式很微妙,因此投票最多的答案存在问题。当使用该程序从第一行数据(例如 HTTP 日志文件)中提取数字时,该程序的输出可以说明这一点。输出看起来是正确的,但数组实际上有很多空元素,并且不会像预期的那样找到存储在$numbers[0] 中的第一个数字。事实上,这是完整的输出:
$ head -1 http | perl prog1.pl
Use of uninitialized value $numbers[0] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[1] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[2] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[3] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[4] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[5] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[6] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[7] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[10] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[11] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[12] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[13] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[14] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[15] in join or string at prog1.pl line 8, <> line 1.
Use of uninitialized value $numbers[16] in join or string at prog1.pl line 8, <> line 1.
200 2206
(请注意,这些数字的缩进显示@numbers 中存在多少个空数组元素,并且当数组转换为字符串时,它们在实际数字之前由空格连接在一起。)
但是,我的解决方案在视觉和实际数组内容中都产生了正确的结果,即 $numbers[0]、$number[1] 等实际上是包含在数据文件。
while (<>) {
my @numbers = m/(\S*\d\S*)/g;
@numbers = grep { $_ eq 1*$_ } @numbers;
print "@numbers\n";
}
$ head -1 http | perl prog2.pl
200 2206
此外,使用 slow 库函数会使其他解决方案的运行速度降低 50%。在 10,000 行数据上运行程序时,输出在其他方面是相同的。