18

给定一个十进制数N作为一串数字,如何M 仅使用正则表达式检查它是否可整除,而不转换为 int?

M=2, 4, 5, 10 是显而易见的。对于 M=3,这里有一些有趣的见解:Regex filter numbers divisible by 3

谁能提供 M=7、9、11、13 等的解决方案?通用的吗?

测试代码(在 python 中,但可以随意使用任何语言):

M = your number, e.g. 2
R = your regexp, e.g., '^[0-9]*[02468]$'

import re
for i in range(1, 2000):
    m = re.match(R, str(i))
    if i % M:
        assert not m, '%d should not match' % i
    else:
        assert m, '%d must match' % i

对于那些好奇的人,这里有一个例子M=3(假设引擎支持递归):

^
(
    | [0369]+ (?1)
    | [147] (?1) [258] (?1)
    | [258] (?1) [147] (?1)
    | ( [258] (?1) ) {3}
    | ( [147] (?1) ) {3}
)
$

更新:有关更多讨论和示例,请参阅此线程。那里发布的表达式结果是错误的(在 70*N 上失败),但“如何到达那里”部分非常有教育意义。

4

6 回答 6

38

或许令人惊讶的结果是这样的正则表达式总是存在的。更令人惊讶的是,它通常没用。

存在结果来自确定性有限自动机之间的对应关系(DFA) 和正则表达式。所以让我们做一个DFA。用 N 表示模数(它不需要是素数),用 B 表示数字基数,对于普通十进制数为 10。N 个状态的 DFA 标记为 0 到 N-1。初始状态为 0。DFA 的符号是数字 0 到 B-1。状态表示输入字符串左前缀的剩余部分,当除以 N 时被解释为整数。边缘表示当您在右侧添加数字时状态的变化。从算术上讲,这是状态映射 S(state,digit) = B * state + digit(模 N)。接受状态为 0,因为零余数表示可分性。所以我们有一个 DFA。DFA 识别的语言和正则表达式识别的语言是一样的,所以存在一个。所以虽然这很有趣,但没有帮助,

如果您想要一个通用算法,很容易在运行时构建这样的 DFA 并通过直接计算填充其状态表。初始化只是一对运行时间为 O(M * N) 的嵌套循环。机器的识别是每个输入字符的恒定时间。这是非常快的,但不使用正则表达式库,如果那是你真正需要的。

在获得一个实际的正则表达式时,我们需要看一下费马小定理。从定理,我们知道 B^(N-1) == 1 (模 N)。例如,当 N=7 和 B=10 时,这意味着每个 6 位数字块都等效于 0 .. 6 范围内的某个单个数字,以实现可分性。指数可以小于N-1;一般来说,它是 N 的欧拉函数的一个因子。称为块 D 的大小。对于 D 个数字块有 N 个正则表达式,每个表示一个特定的等价类余数模 N。这些表达式最多有长度 O(B^D),很大。对于 N=7,这是一组一百万个字符长的正则表达式;我想这会破坏大多数正则表达式库。

这与示例代码中的表达式如何工作有关;该表达式(?1)匹配等于 0 (mod 3) 的字符串。这适用于 N=3,因为 10^1 == 1 (mod 3) 这意味着 A0B == AB (mod 3)。这个在指数大于1的时候比较复杂,但是原理是一样的。(请注意,示例代码使用的识别器不仅仅是正则表达式,严格来说。)表达式[0369][147][258]是模 3 表达式中数字 0、1 和 2 的正则表达式。概括地说,您将以类似的方式使用上述正则表达式数字。

我没有提供代码,因为(1)编写时间比这个答案要长,(2)我真的怀疑它会在任何已知的实现中执行。

于 2012-11-04T23:08:52.967 回答
6

如果您的数字是基于一元的,您可以使用此正则表达式:s/1{divisor}//g然后测试数字是否为空。

这是一种 Perl 方法

my @divs = (2,3,5,7,11,13);
for my $num(2..26) {
    my $unary = '1'x$num; # convert num to unary
    print "\n$num can be divided by : ";
    for(@divs) {
        my $test = $unary;
        $test =~ s/1{$_}//g;
        print "$_, " unless $test;
    }
}

输出:

2 can be divided by : 2, 
3 can be divided by : 3, 
4 can be divided by : 2, 
5 can be divided by : 5, 
6 can be divided by : 2, 3, 
7 can be divided by : 7, 
8 can be divided by : 2, 
9 can be divided by : 3, 
10 can be divided by : 2, 5, 
11 can be divided by : 11, 
12 can be divided by : 2, 3, 
13 can be divided by : 13, 
14 can be divided by : 2, 7, 
15 can be divided by : 3, 5, 
16 can be divided by : 2, 
17 can be divided by : 
18 can be divided by : 2, 3, 
19 can be divided by : 
20 can be divided by : 2, 5, 
21 can be divided by : 3, 7, 
22 can be divided by : 2, 11, 
23 can be divided by : 
24 can be divided by : 2, 3, 
25 can be divided by : 5, 
26 can be divided by : 2, 13, 
于 2012-09-14T11:58:00.850 回答
4

这是一个老问题,但现有的答案都不包括代码。早在 2010 年,我就编写了计算这些正则表达式的代码,该代码在此处在线,并有一个指向注释源代码的链接,所以我认为在此处添加一个链接可能会很有用。

该技术基本上是eh9 的答案中描述的技术,除了我使用状态消除直接从 DFA 计算正则表达式,然后对结果进行一些简化。它们是普通的正则表达式,没有递归。(使用递归会使结果更短,但我认为有趣的是,没有它是可能的。)

结果并不eh9 的估计所暗示的那样冗长。例如,这是一个匹配以 10 为底的 7 的倍数的正则表达式:

^(0|7|[18]5*4|(2|9|[18]5*6)(3|[29]5*6)*(1|8|[29]5*4)|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))|(4|[18]5*[18]|(2|9|[18]5*6)(3|[29]5*6)*(5|[29]5*[18])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(2|9|35*4|(4|35*6)(3|[29]5*6)*(1|8|[29]5*4)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4)))|(5|[18]5*[29]|(2|9|[18]5*6)(3|[29]5*6)*(6|[29]5*[29])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(4|[18]5*[18]|(2|9|[18]5*6)(3|[29]5*6)*(5|[29]5*[18])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))(4|[07]5*[29]|(1|8|[07]5*6)(3|[29]5*6)*(6|[29]5*[29])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))*(6|[07]5*4|(1|8|[07]5*6)(3|[29]5*6)*(1|8|[29]5*4)|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(2|9|35*4|(4|35*6)(3|[29]5*6)*(1|8|[29]5*4)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))))|(6|[18]5*3|(2|9|[18]5*6)(3|[29]5*6)*(0|7|[29]5*3)|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3))|(4|[18]5*[18]|(2|9|[18]5*6)(3|[29]5*6)*(5|[29]5*[18])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(1|8|35*3|(4|35*6)(3|[29]5*6)*(0|7|[29]5*3)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3)))|(5|[18]5*[29]|(2|9|[18]5*6)(3|[29]5*6)*(6|[29]5*[29])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(4|[18]5*[18]|(2|9|[18]5*6)(3|[29]5*6)*(5|[29]5*[18])|(3|[18]5*[07]|(2|9|[18]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))(4|[07]5*[29]|(1|8|[07]5*6)(3|[29]5*6)*(6|[29]5*[29])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))*(5|[07]5*3|(1|8|[07]5*6)(3|[29]5*6)*(0|7|[29]5*3)|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(1|8|35*3|(4|35*6)(3|[29]5*6)*(0|7|[29]5*3)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3)))))(2|9|45*3|(5|45*6)(3|[29]5*6)*(0|7|[29]5*3)|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3))|(0|7|45*[18]|(5|45*6)(3|[29]5*6)*(5|[29]5*[18])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(1|8|35*3|(4|35*6)(3|[29]5*6)*(0|7|[29]5*3)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3)))|(1|8|45*[29]|(5|45*6)(3|[29]5*6)*(6|[29]5*[29])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(0|7|45*[18]|(5|45*6)(3|[29]5*6)*(5|[29]5*[18])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))(4|[07]5*[29]|(1|8|[07]5*6)(3|[29]5*6)*(6|[29]5*[29])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))*(5|[07]5*3|(1|8|[07]5*6)(3|[29]5*6)*(0|7|[29]5*3)|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(1|8|35*3|(4|35*6)(3|[29]5*6)*(0|7|[29]5*3)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(4|65*3|(0|7|65*6)(3|[29]5*6)*(0|7|[29]5*3)))))*(3|45*4|(5|45*6)(3|[29]5*6)*(1|8|[29]5*4)|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))|(0|7|45*[18]|(5|45*6)(3|[29]5*6)*(5|[29]5*[18])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(2|9|35*4|(4|35*6)(3|[29]5*6)*(1|8|[29]5*4)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4)))|(1|8|45*[29]|(5|45*6)(3|[29]5*6)*(6|[29]5*[29])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(0|7|45*[18]|(5|45*6)(3|[29]5*6)*(5|[29]5*[18])|(6|45*[07]|(5|45*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))(4|[07]5*[29]|(1|8|[07]5*6)(3|[29]5*6)*(6|[29]5*[29])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(0|7|35*[29]|(4|35*6)(3|[29]5*6)*(6|[29]5*[29])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(3|65*[29]|(0|7|65*6)(3|[29]5*6)*(6|[29]5*[29]))))*(6|[07]5*4|(1|8|[07]5*6)(3|[29]5*6)*(1|8|[29]5*4)|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))|(3|[07]5*[18]|(1|8|[07]5*6)(3|[29]5*6)*(5|[29]5*[18])|(2|9|[07]5*[07]|(1|8|[07]5*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))(6|35*[18]|(4|35*6)(3|[29]5*6)*(5|[29]5*[18])|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(2|9|65*[18]|(0|7|65*6)(3|[29]5*6)*(5|[29]5*[18])))*(2|9|35*4|(4|35*6)(3|[29]5*6)*(1|8|[29]5*4)|(5|35*[07]|(4|35*6)(3|[29]5*6)*(4|[29]5*[07]))(1|8|65*[07]|(0|7|65*6)(3|[29]5*6)*(4|[29]5*[07]))*(5|65*4|(0|7|65*6)(3|[29]5*6)*(1|8|[29]5*4))))))*$

这是“仅” 12,733 个字符,并且在我尝试过的实现中运行良好。


PS。为了看看使用递归有多不有趣,这里有一个 Perl 程序,它使用递归正则表达式测试可被 7 整除:

my $re = qr{
  ^($|[07](?1)|[18](?2)|[29](?3)|3(?4)|4(?5)|5(?6)|6(?7))
  |(?!)(?:
      ([07](?4)|[18](?5)|[29](?6)|3(?7)|4(?1)|5(?2)|6(?3))
    | ([07](?7)|[18](?1)|[29](?2)|3(?3)|4(?4)|5(?5)|6(?6))
    | ([07](?3)|[18](?4)|[29](?5)|3(?6)|4(?7)|5(?1)|6(?2))
    | ([07](?6)|[18](?7)|[29](?1)|3(?2)|4(?3)|5(?4)|6(?5))
    | ([07](?2)|[18](?3)|[29](?4)|3(?5)|4(?6)|5(?7)|6(?1))
    | ([07](?5)|[18](?6)|[29](?7)|3(?1)|4(?2)|5(?3)|6(?4))
  )
}x;

while (<>) {
    print(/$re/ ? "matches\n" : "does not match\n");
}

这只是 DFA 作为递归正则表达式的直接表达。

于 2017-09-26T16:45:24.290 回答
2

如果允许修改字符串并重复,则可以一次进行一步长除法。7 的 sed 语法:重新申请,直到获得剩余部分。当你有一个 0、1、2、3、4、5 或 6 时停止。

s/^0//
s/^7/0/
s/^8/1/
s/^9/2/
s/^([18]4|[29][18]|35|4[29]|56|63)/0/
s/^([18]5|[29][29]|36|43|5[07]|64)/1/
s/^([18]6|[29]3|3[07]|44|5[18]|65)/2/
s/^([18][07]|[29]4|3[18]|45|5[29]|66)/3/
s/^([18][18]|[29]5|3[29]|46|53|6[07])/4/
s/^([18][29]|[29]6|33|4[07]|54|6[18])/5/
s/^([18]3|[29][07]|34|4[18]|55|6[29])/6/

但它是非常弱的酱汁。更容易完全取消“正则表达式”,只需一次读取一个字符并切换到适当的状态。如果这不是一个选项,那么我怀疑你对 7 和 13 不走运,尽管 11 可能仍然是可能的。

于 2012-11-04T02:10:42.507 回答
1

这是一个通用的直接递归蛮力长除法。它没有优化,绝对不是优雅的大声笑。它在 JavaScript 中(下面是带有代码的测试 html 页面):

<!doctype html>
<html>
<head>
<script type="text/javascript">
function isNDivisibleByM(N, M) {
    var copyN = N;
    var MLength = (""+M).length;
    var multiples = [];
    for(var x = 0; x < M; x++)
        multiples[x] = [];
    for(var i = M, x=0; i < M*10; x=0) {
        for(var j = i; j < i+M; j++, x++)
            multiples[x].push(j);
        i+=M;
    }
    var REs = [];
    for(var x = 0; x < M; x++)
        REs[x] = new RegExp("^("+multiples[x].join("|")+")");
    while(N.length >= MLength) {
        var sameLen = (N.length == MLength);
        for(var x = 0; x < M; x++)
            N = N.replace(REs[x], (x==0)?"":(""+x));            
        N = N.replace(/^0/g, "");           
        if(sameLen) break;
    }
    N = N.replace(/^0/g, "");
    var numericN = parseInt(copyN);
    if(N.length == 0) {
        if(numericN%M!=0) {
            console.error("Wrong claim: " + copyN + " NOT divisible by " + M);
        }
        return true;
    }
    if(numericN%M==0 && N.length != 0) {
        console.error("Missed claim: " + copyN + " IS divisible by " + M + " - " + N + " is: " + copyN);
    }
    return false;
}
function run() {
    alert(isNDivisibleByM((""+document.getElementById("N").value), parseInt(document.getElementById("M").value)));
}
</script>
</head>
<body>
<label>N:</label><input type="text" id="N" />
<label>M:</label><input type="text" id="M" />
<button onclick="run()">Is N divisible by M?</button>
</body>
</html>

这个想法适用于 M = 7(示例):

while(numStr.length > 1) {
    numStr = numStr.replace(/^(14|21|35|42|56|63)/, "");
    numStr = numStr.replace(/^(15|22|36|43|50|64)/, "1");
    numStr = numStr.replace(/^(16|23|30|44|51|65)/, "2");
    numStr = numStr.replace(/^(10|24|31|45|52|66)/, "3");
    numStr = numStr.replace(/^(11|25|32|46|53|60)/, "4");
    numStr = numStr.replace(/^(12|26|33|40|54|61)/, "5");
    numStr = numStr.replace(/^(13|20|34|41|55|62)/, "6");
}
于 2012-11-08T06:04:29.833 回答
0

尽管这个问题很有趣,但我认为除了您列出的“明显”问题之外,其他任何事情都不可能发生。

大多数可分规则都需要数学运算。


您可以使用前瞻来测试多个要求的字符串,以便您可以将成对的“明显”要求组合在一起(2 x 3、3 x 5 等):

使用 .匹配 6 个字母的单词很容易\b\w{6}\b。匹配包含“cat”的单词同样容易:\b\w*cat\w*\b.

结合两者,我们得到:(?=\b\w{6}\b)\b\w*cat\w*\b用 RegexBuddy 分析这个正则表达式。简单的!这是它的工作原理。在尝试正则表达式的字符串中的每个字符位置,引擎将首先在正前瞻内尝试正则表达式。只有当字符串中的当前字符位置位于字符串中 6 个字母单词的开头时,此子正则表达式以及因此的前瞻才匹配。如果不是,则前瞻将失败,并且引擎将从字符串中的下一个字符位置开始继续尝试正则表达式。

于 2012-09-13T10:21:30.993 回答