1

我正在尝试提出一个匹配任何不是 32 位整数的正则表达式。我的最终目标是匹配不符合以下格式的行

Integer\tInteger\tInteger\tInteger\tInteger\tInteger\tInteger

(7 个 32 位整数和每个整数之间的 1 个制表符)

到目前为止,我已经想出了这个

#!/usr/bin/perl -w
use strict;
while ( my $line = <> ) {

    if ( $line =~ /^(429496729[0-6]|42949672[0-8]\d|4294967[01]\d{2}|429496[0-6]\d{3}|42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|4[01]\d{8}|[1-3]\d{9}|[1-9]\d{8}|[1-9]\d{7}|[1-9]\d{6}|[1-9]\d{5}|[1-9]\d{4}|[1-9]\d{3}|[1-9]\d{2}|[1-9]\d|\d)$/ ) {

        print "Match at line $.\n";
        print "$line"
    }

}

但我什至无法迈出让正则表达式匹配 32 位数字的第一步(一旦我解决了这个问题,我就可以解决让标签成为他们需要的方式)

我是否以正确的方式解决了这个问题?有什么想法吗?

4

3 回答 3

6

我是否以正确的方式解决了这个问题?

假设确实需要验证,我的第一种方法是拆分选项卡,检查字段数,检查每个字段,但不使用正则表达式。在正则表达式中进行范围检查是愚蠢的!(使用 sprintf 填充然后进行字符串比较将解决溢出问题。)

其他问题:

  • \d比赛远不止0-9。如果您只想匹配 0-9,请使用/\d/aor 。/[0-9]/
  • 负数呢?32 位整数也可用于存储 2147483647..-2147483648。
  • 前导零和前导加号或减号呢?
  • 千位分隔符呢?
  • 10.0整数吗?从数学上讲,是的。Perl 也会把它存储为一个整数。
于 2012-10-10T05:18:41.460 回答
2

我会说不,这不是正确的方法 -尝试遵循该正则表达式非常困难;虽然可以做到,但请考虑明天是否有意义。或者如果范围发生变化或需要对格式稍作变化,那么改变的难度有多大:)

以下是我的建议:

  1. 阅读它是一个数字吗?找出如何判断一个值是否为数字,如果是,则将其提取为一个。也就是说,获取一个实数值,而不是字符串。如果需要限制“有效”数字是什么,可以在此阶段进行额外检查;不限制范围,只限制格式

  2. 对提取的数字使用简单的范围检查 - 在这种情况下,介于 0 和 2 32 -1 之间?

于 2012-10-10T06:10:16.667 回答
2

您可以在正则表达式中完成所有操作,但最好将它们视为数字并使用数学。

# Split it into fields.
my @fields = split /\t/, $line;

# Scan for fields which do not look like integers
# or are outside the unsigned 32 bit integer range
my $valid_line = !grep { /[^0-9]/ || ($_ < 0) || (2**32-1 < $_) } @fields;

其他答案中关于“什么是 32 位整数”的所有警告仍然适用。“+10”有效吗?“10.0”?在不知道为什么要过滤这些数字的情况下无法回答这个问题,请根据需要调整逻辑。

只是为了插入一个perl5i插件......

use perl5i::2;
my $valid_line = !grep { $_->is_integer && ($_ < 0) || (2**32-1 < $_) } @fields;
于 2012-10-10T06:50:52.173 回答