使用正则表达式来比较数字

时间:2012-02-24 16:59:43

标签: regex

所以这是一个明显的例子,“你做错了”。我实际上并不打算这样做,但是工作中的谈话引发了这个问题:

  

是否可以生成正则表达式来确定整数是否小于任意值。

对于某些值,这很容易。对于小于1000的整数,\ d {1,3}应该可以解决问题。对于整数< 500,它有点棘手,但不是那么糟糕,因为你可以使用[0-4] {0,1} \ d {1,2}。

一旦你达到任意值,就会有很多琐事。例如,小于255的所有数字都类似于\ d {1,2} | [0-1] \ d {2} | [2] [0-4] \ d | [2] [5] [0-4]。

这里有一个正则表达式吗?或者你必须以编程方式生成正则表达式吗?

(再次,让我指出我并不打算这样做。显然,在你最喜欢的编程语言中使用“foo< bar”会更有效率和易读性。)

2 个答案:

答案 0 :(得分:3)

您将需要为每个边界数生成表达式。假设有一个正则表达式可以完成这项工作。然后,正则表达式必须能够将某些字符序列作为输入。但是,我们知道正则表达式和有限状态自动机是等价的,所以这与我们可以构造FSM相同,因为可能的数字是无界的,这将需要无限数量的状态,这与FSA的定义相矛盾。 / p>

答案 1 :(得分:2)

这很容易。

#!/usr/bin/env perl
use strict;
use warnings;
use Regexp::Assemble;

for my $n (@ARGV)  {
    my $asm = new Regexp::Assemble;
    for (1 .. $n) { $asm->add($_) }
    for ($asm->re){
        s/\)$/\$/;
        s/^[^:]*:/^/;
        print "$n => /$_/\n";
    }
}

现在运行它以找到匹配1和该数字之间的整数的模式:

$ perl /tmp/ra 5 15 153 401 1144
5 => /^[12345]$/
15 => /^(?:[23456789]|1[012345]?)$/
153 => /^(?:1(?:[6789]|5[0123]?|0\d?|1\d?|2\d?|3\d?|4\d?)?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)$/
401 => /^(?:1(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|2(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|3(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|4(?:[123456789]|0[01]?)?|5\d?|6\d?|7\d?|8\d?|9\d?)$/
1144 => /^(?:1(?:0(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|1(?:[56789]|4[01234]?|0\d?|1\d?|2\d?|3\d?)?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|2(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|3(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|4(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|5(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|6(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|7(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|8(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?|9(?:0\d?|1\d?|2\d?|3\d?|4\d?|5\d?|6\d?|7\d?|8\d?|9\d?)?)$/