Python Challenge 第10关(正则表达式)

来源:互联网 发布:奥卡姆剃刀原理 知乎 编辑:程序博客网 时间:2024/04/28 13:57

这一关乍一看很像行测题

给了一个未完成的序列,让推断第31个数的长度,瞪了好久怎么也没发现给出的这5个数字有什么关系。。。百度。。。原来每个数都是对前一个数的描述。如1,11,21,1211,那1211的意思就是前一个数有1个2,1个1。规律找到程序就不难写了。

然后一个丑陋的程序就诞生了:

elem='1'for index in range(1,31):    newelem=''    pos=0    while pos<len(elem):        beg=elem[pos]        count=0        while pos<len(elem) and elem[pos]==beg:            pos+=1            count+=1        newelem+=str(count)+beg    elem=newelemprint len(elem)

逻辑之复杂,一点也不pythonic。


看看答案。。。原来这是一个正则表达式的问题。可以简单的描述为寻找包含连续的相同的数字序列的问题。如1113334555,找到其中的111,333,4,555。

答案如下:

import redef describe(s):    return "".join([str(len(m.group(0))) + m.group(1) for m in re.finditer(r"(\d)\1*", s)])s = "1"for dummy in range(30):    s = describe(s)print len(s)  # prints 5808


上述代码中不熟悉的有3块:

1、group的用法

2、finditer函数

3、正则表达式的写法:r"(\d)\1*"


OK,一点一点的来。先看group。

在正则表达式中引入分组的目的是为了匹配多个字符的重复情况,比如匹配abcabcabc这样的。python里关于group有以下几个函数:

group()==group(0):这两个函数都是为了获取整个成功匹配的字符串,跟括号没关系。

group(index):返回匹配第index个group的字符串。这句话乍一看没问题,仔细琢磨就觉得有歧义了。首先index是从1开始的,那么:

m=re.search(r"(\d\d)+","12345678")print m.group()print m.groups()print m.group(1)
输出是什么呢?

第一条语句输出“12345678”,还是说跟括号无关,第二条语句输出("78",),不用说第三条语句就是输出“78”了。

(\d\d)并没有12345678分成四组,而是只匹配了最后的78,也就是说在这次匹配中因为只有一对小括号,所以只有一个group,而这个个group还是记录最后一次匹配成功的结果。

groups():输出的就是一个元组,即(group(1),group(2),...)。findall函数得到的groups的序列,比如:

>>> rst=re.search('(\d\w)(\w\d)','1dd21fg2')>>> rst.group()'1dd2'>>> rst.groups()('1d', 'd2')>>> re.findall('(\d\w)(\w\d)','1dd21fg2')[('1d', 'd2'), ('1f', 'g2')]

finditer函数和findall有点类似,只不过findall输出的是匹配成功的字符串(或元组)的list,而finditer输出的匹配成功的对象的迭代器。相对于search得到一个结果,findall和finditer得到所有的匹配结果。


最后一个是“奇怪”的正则表达式的写法,这个\1的意思是前面所出现的第一个group,自然(\d)\1*就表示重复出现的数字,另外,不要忘了最前面的小r。


                                             
0 0