正则表达数与合数判定

quhao那里,了解到这样一篇文章:牛B的正则表达式:素数判定与线性方程求解

今天又学到一个牛B东西。你相信吗?正则表达式竟然可以用来判定素数,甚至可以用来解方程!下面这段正则表达式可以用来判断,一个字符串的长度是否为合数(假设这个字符串里全是字符’1′):
^1?$|^(11+?)\1+$

初看上去,这条正则式怪怪的。不过,略为分析一下,它就原形毕露。

中间的备选符竖线把正则式分数两部分,^1?$和^(11+?)\1+$。

先看第1部分。
^1?$匹配的是,行首,1个或者0个’1‘,行尾。
换言之,它匹配的是一个空行或者只含一个’1‘的行。

再看第二部分。
先说一下正则式的基本规则。

  • +:量词,表示前面一个单位的一次或多次重复。
  • ?:量词,表示前面一个单位的出现0次或1次。
  • +?:连用,表示前面一个单位的一次或多次重复,不过倾向于越少越好。正所谓:懒惰模式。
  • ():捕获。这里面的内容重复出现时,可以使用\1,\2之类的代词来表示。

我们切入正题。
^(11+?)\1+$
,它匹配的是,
行首,紧接着是由’1‘和m个1组成的捕获组(m是大于等于1的自然数),紧接着是N个这样的捕获组(n是大于等于1的自然数,n与m不必相等)。

11+?和\1+是理解这条正则表达式的关键。
我们再细分一下。

  • 1,匹配1个’1‘,仅此而已;
  • 1+?不能再分,它匹配的是1次或更多次的’1‘(为了表示方便,该次数我们用m来表示),?表示懒惰式匹配。因此,11+?可以表示为(1+m)个1
  • \1 表示前面所捕获的括号内的内容。后边又一个+,它匹配的是1次或更多次的’\1‘(为了表示方便,该次数我们用n来表示)。

这样,我们澄清了这条正则式试图表达的意思:
^(11+?)\1+$,它匹配的是由(1+m)(1+n)个1组成的字串。其中m和n都是大于等于1的自然数。n和m可以相等,也可以不相等。

全局来看,^1?$|^(11+?)\1+$匹配的是一个空行,或者一个’1‘,或者(1+m)(1+n)个’1‘。

(1+m)(1+n)的集合是什么样的数呢?连编程都不用,我直接在excel里列了一张表格:

考虑到n和m相等的情况会出现对称。我们只考虑其中一半即可:

即,得到的数列为:

4,6,8,9,10,12,14,15,16,18,20,…

从其产生的规则来说,上面的数全是合数(均由乘积构成);但是,上面这些数列是否就等同于合数集,这就不是我能证明的了,给数学系的同学去证明吧。

值得补充的一点是,上面两个图表只是使用的后半部分的正则式,即只有^(11+?)\1+$不包括^1?$。如果按照原正则式补全,此数列就会变成:

0,1,4,6,8,9,10,12,14,15,16,18,20,…

根据合数的定义,0和1是不包括在内的。不知原作者为什么把0和1也要囊括进来。

虽如此,我十分佩服写出这条正则式的大牛。理解其含义之后,我也会心微笑。同理,我们还可以构造许多类似的正则式,只要满足两个条件,一是你知道有某条简洁的公式;二是你知道如何使用正确的正则语法来表达出来。

PS:

原贴中有一条例子是三元一次方程11x + 2y + 5z = 115

^(.*)\1{10}(.*)\2{1}(.*)\3{4}$

解密:此处的.*共出现3次,互不约束,当然是三元一次

2008年4月1日10:00

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">