这一关乍一看很像行测题
给了一个未完成的序列,让推断第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=newelem
print len(elem)
逻辑之复杂,一点也不pythonic。
看看答案。。。原来这是一个正则表达式的问题。可以简单的描述为寻找包含连续的相同的数字序列的问题。如1113334555,找到其中的111,333,4,555。
答案如下:
import re
def 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*"
在正则表达式中引入分组的目的是为了匹配多个字符的重复情况,比如匹配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。