匹配有限自然数系列

时间:2012-02-15 16:21:09

标签: regex perl

如何将有限natural number系列与正则表达式匹配?

所以,要求是:

  • 字符串包含数字和空格(作为分隔符)
  • 第一个号码是1
  • 每个数字(第一个除外)等于前一个数字+ 1

应匹配

  • 1
  • 1 2
  • 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  • 从1到10 ^ 1000
  • 的一系列后续数字

不应匹配

  • ``
  • 1 3 4
  • 1 2 3 4 5 6 6

除此之外,regex还有一些要求:

  • 它应该是单一的一次性表达式,而不是一个循环条件算法的指令包
  • 它可以使用perl正则表达式
  • 的所有功能

我不确定正则表达式是否实际上是懒惰的,所以如果它们会很好。因为自然数系列在数论中的原始含义是非有限的。

最后一个。请注意,我使用错误的工具完成该工作。它根本不是真正的编程任务。

3 个答案:

答案 0 :(得分:7)

你走了。在Perl v5.10到v5.14上测试过。关键是 递归模式 ,我们根据(?&Sequence)规则进行递归。这是一种归纳证明。

如果您真的想要从bigint生成序列,那么1 .. 10**10_000就是存在的。如果您可以将自己限制为机器本机整数,32位或64位,具体取决于您的平台,它将运行得更快。

#!/usr/bin/env perl
use v5.10;
use bigint;  # only if you need stuff over maxint

my $pat = qr{
    ^
    (?= 1 \b )
    (?<Sequence>
        (?<Number> \d+ )
        (?:
            \s+
            (??{  "(?=" . (1 + $+{Number}) . ")" })
            (?&Sequence)
        )?
    )
    $
}x;

# first test embedded data
while (<DATA>) {
    if ( /$pat/ ) {
        print "PASS: ", $_;

    } else {
        print "FAIL: ", $_;
    }
}

# now generate long sequences
for my $big ( 2, 10, 25, 100, 1000, 10_000, 100_000 ) {
    my $str = q();
    for (my $i = 1; $i <= $big; $i++) {
        $str .= "$i ";
    }
    chop $str;
    if ($str =~ $pat) {
        print "PASS: ";
    } else {
        print "FAIL: ";
    }
    if (length($str) > 60) {
        my $len = length($str);
        my $first = substr($str,   0, 10);
        my $last  = substr($str, -10);
        $str = $first . "[$len chars]" . $last;
    }
    say $str;

}


__END__
5
fred
1
1 2 3
1 3 2
1 2 3 4 5
1 2 3 4 6
2 3 4 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
1 2 3 4 5 6 6

哪个运行产生:

FAIL: 5
FAIL: fred
PASS: 1
PASS: 1 2 3
FAIL: 1 3 2
PASS: 1 2 3 4 5
FAIL: 1 2 3 4 6
FAIL: 2 3 4 6
PASS: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
FAIL: 1 2 3 4 5 6 6
PASS: 1 2
PASS: 1 2 3 4 5 6 7 8 9 10
PASS: 1 2 3 4 5 [65 chars]2 23 24 25
PASS: 1 2 3 4 5 [291 chars] 98 99 100
PASS: 1 2 3 4 5 [3892 chars]8 999 1000
PASS: 1 2 3 4 5 [588894 chars]999 100000

冒着看似自私的风险,a book涵盖了这种事情。请参阅 Programming Perl ,4ᵗʰ版本第5章中的“花式模式”部分。您需要查看“命名组”,“递归模式”和“语法模式”的新章节。这本书是在打印机上的,应该在一两天内以电子方式提供。

答案 1 :(得分:3)

尝试下一个正则表达式(在perl中):

m/\A((??{ our $i += 1 })(?>\s*))+\Z/

<强>测试

script.pl的内容:

use warnings;
use strict;

while ( <DATA> ) { 
    chomp;
    our $i = 0;
    printf qq[%s\n], $_ if m/\A((??{ our $i += 1 })(?>\s*))+\Z/;
}

__DATA__
0
2
1
1 3 4
1 2
1 2 3 4 5 6 6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
2 1
1 2 3 4 5 7
1           2            3    

运行脚本:

perl script.pl

结果:

1
1 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
1           2            3 

答案 2 :(得分:2)

我认为没有可能满足您要求的模式,因为正则表达式主要与文本匹配;匹配时没有计算

然而,您可以构建自己的自动机来执行计算,或者只是迭代数字,这应该更有效率