打开开源中国提供的正则表达式测试工具http://tool.oschina.net/regex/,输入待匹配的文本,然后选择常用的正则表达式,就可以得出相应的匹配结果了。例如,这里输入待匹配的文本如下:
Hello, my phone number is 010-86432100 and email is cqc@cuiqingcai.com, and my website is http://cuiqingcai.com.
1
Hello, my phone number is 010-86432100 and email is cqc@cuiqingcai.com, and my website is http://cuiqingcai.com.
match()方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,就返回匹配成功的结果;如果不匹配,就返回None。示例如下:
import re
content = ‘Hello 123 4567 World_This is a Regex Demo’
print(len(content))
result = re.match(‘^Hello\s\d\d\d\s\d{4}\s\w{10}’, content)
print(result)
print(result.group())
print(result.span())
12345678
import re content = ‘Hello 123 4567 World_This is a Regex Demo’print(len(content))result = re.match(‘^Hello\s\d\d\d\s\d{4}\s\w{10}’, content)print(result)print(result.group())print(result.span())
这里可以使用()括号将想提取的子字符串括起来。()实际上标记了一个子表达式的开始和结束位置,被标记的每个子表达式会依次对应每一个分组,调用group()方法传入分组的索引即可获取提取的结果。示例如下:
import re
content = ‘Hello 1234567 World_This is a Regex Demo’
result = re.match(‘^Hello\s(\d+)\sWorld’, content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())
12345678
import re content = ‘Hello 1234567 World_This is a Regex Demo’result = re.match(‘^Hello\s(\d+)\sWorld’, content)print(result)print(result.group())print(result.group(1))print(result.span())
接着上面的例子,我们可以改写一下正则表达式:
import re
content = ‘Hello 123 4567 World_This is a Regex Demo’
result = re.match(‘^Hello.*Demo$’, content)
print(result)
print(result.group())
print(result.span())
1234567
import re content = ‘Hello 123 4567 World_This is a Regex Demo’result = re.match(‘^Hello.*Demo$’, content)print(result)print(result.group())print(result.span())
这里我们将中间部分直接省略,全部用.*来代替,最后加一个结尾字符串就好了。运行结果如下:
<_sre.SRE_Match object; span=(0, 41), match=’Hello 123 4567 World_This is a Regex Demo’>
Hello 123 4567 World_This is a Regex Demo
(0, 41)
123
<_sre.SRE_Match object; span=(0, 41), match=’Hello 123 4567 World_This is a Regex Demo’>Hello 123 4567 World_This is a Regex Demo(0, 41)
使用上面的通用匹配.*时,可能有时候匹配到的并不是我们想要的结果。看下面的例子:
import re
content = ‘Hello 1234567 World_This is a Regex Demo’
result = re.match(‘^He.*(\d+).*Demo$’, content)
print(result)
print(result.group(1))
123456
import re content = ‘Hello 1234567 World_This is a Regex Demo’result = re.match(‘^He.*(\d+).*Demo$’, content)print(result)print(result.group(1))
这里我们依然想获取中间的数字,所以中间依然写的是(\d+)。而数字两侧由于内容比较杂乱,所以想省略来写,都写成 .*。最后,组成^He.*(\d+).*Demo$,看样子并没有什么问题。我们看下运行结果:
<_sre.SRE_Match object; span=(0, 40), match=’Hello 1234567 World_This is a Regex Demo’>
7
12
<_sre.SRE_Match object; span=(0, 40), match=’Hello 1234567 World_This is a Regex Demo’>7
但这很明显会给我们带来很大的不便。有时候,匹配结果会莫名其妙少了一部分内容。其实,这里只需要使用非贪婪匹配就好了。非贪婪匹配的写法是.*?,多了一个?,那么它可以达到怎样的效果?我们再用实例看一下:
import re
content = ‘Hello 1234567 World_This is a Regex Demo’
result = re.match(‘^He.*?(\d+).*Demo$’, content)
print(result)
print(result.group(1))
123456
import re content = ‘Hello 1234567 World_This is a Regex Demo’result = re.match(‘^He.*?(\d+).*Demo$’, content)print(result)print(result.group(1))
这里我们只是将第一个.*改成了.*?,转变为非贪婪匹配。结果如下:
<_sre.SRE_Match object; span=(0, 40), match=’Hello 1234567 World_This is a Regex Demo’>
1234567
12
<_sre.SRE_Match object; span=(0, 40), match=’Hello 1234567 World_This is a Regex Demo’>1234567
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。我们用实例来看一下:
import re
content = ”’Hello 1234567 World_This
is a Regex Demo
”’
result = re.match(‘^He.*?(\d+).*?Demo$’, content)
print(result.group(1))
1234567
import re content = ”’Hello 1234567 World_Thisis a Regex Demo”’result = re.match(‘^He.*?(\d+).*?Demo$’, content)print(result.group(1))
和上面的例子相仿,我们在字符串中加了换行符,正则表达式还是一样的,用来匹配其中的数字。看一下运行结果:
AttributeError Traceback (most recent call last)
<ipython-input-18-c7d232b39645> in <module>()
5 ”’
6 result = re.match(‘^He.*?(\d+).*?Demo$’, content)
—-> 7 print(result.group(1))
AttributeError: ‘NoneType’ object has no attribute ‘group’
1234567
AttributeError Traceback (most recent call last)<ipython-input-18-c7d232b39645> in <module>() 5 ”’ 6 result = re.match(‘^He.*?(\d+).*?Demo$’, content)—-> 7 print(result.group(1)) AttributeError: ‘NoneType’ object has no attribute ‘group’
前面提到过,match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了。我们看下面的例子:
import re
content = ‘Extra stings Hello 1234567 World_This is a Regex Demo Extra stings’
result = re.match(‘Hello.*?(\d+).*?Demo’, content)
print(result)
12345
import re content = ‘Extra stings Hello 1234567 World_This is a Regex Demo Extra stings’result = re.match(‘Hello.*?(\d+).*?Demo’, content)print(result)
另外,由于代码有换行,所以这里第三个参数需要传入re.S。整个匹配代码如下:
result = re.search(‘<li.*?active.*?singer=”(.*?)”>(.*?)</a>’, html, re.S)
if result:
print(result.group(1), result.group(2))
123
result = re.search(‘<li.*?active.*?singer=”(.*?)”>(.*?)</a>’, html, re.S)if result: print(result.group(1), result.group(2))
由于需要获取的歌手和歌名都已经用小括号包围,所以可以用group()方法获取。
运行结果如下:
齐秦 往事随风
1
齐秦 往事随风
可以看到,这正是class为active的li节点内部的超链接包含的歌手名和歌名。
如果正则表达式不加active(也就是匹配不带class为active的节点内容),那会怎样呢?我们将正则表达式中的active去掉,代码改写如下:
result = re.search(‘<li.*?singer=”(.*?)”>(.*?)</a>’, html, re.S)
if result:
print(result.group(1), result.group(2))
123
result = re.search(‘<li.*?singer=”(.*?)”>(.*?)</a>’, html, re.S)if result: print(result.group(1), result.group(2))
注意,在上面的两次匹配中,search()方法的第三个参数都加了re.S,这使得.*?可以匹配换行,所以含有换行的li节点被匹配到了。如果我们将其去掉,结果会是什么?代码如下:
result = re.search(‘<li.*?singer=”(.*?)”>(.*?)</a>’, html)
if result:
print(result.group(1), result.group(2))
123
result = re.search(‘<li.*?singer=”(.*?)”>(.*?)</a>’, html)if result: print(result.group(1), result.group(2))
在上面的HTML文本中,如果想获取所有li节点的歌名,直接用正则表达式来提取可能比较烦琐。比如,可以写成这样子:
results = re.findall(‘<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>’, html, re.S)
for result in results:
print(result[1])
123
results = re.findall(‘<li.*?>\s*?(<a.*?>)?(\w+)(</a>)?\s*?</li>’, html, re.S)for result in results: print(result[1])
运行结果如下:
一路上有你
沧海一声笑
往事随风
光辉岁月
记事本
但愿人长久
123456
一路上有你沧海一声笑往事随风光辉岁月记事本但愿人长久
此时借助sub()方法就比较简单了。可以先用sub()方法将a节点去掉,只留下文本,然后再利用findall()提取就好了:
html = re.sub(‘<a.*?>|</a>’, ”, html)
print(html)
results = re.findall(‘<li.*?>(.*?)</li>’, html, re.S)
for result in results:
print(result.strip())
12345
html = re.sub(‘<a.*?>|</a>’, ”, html)print(html)results = re.findall(‘<li.*?>(.*?)</li>’, html, re.S)for result in results: print(result.strip())
for i in range(30):
x=random.randint(10,200)
y=random.randint(10,200)
red=random.randint(0,255)
green=random.randint(0,255)
blue=random.randint(0,255)
color(red,green,blue)
penup()
goto(x,y)
dot(x/5)
pendown()
time.sleep(5)
import os
import pandas as pd
excels=[pd.read_excel(fname)
for fname in os.listdir("./")
#if ".xlsx" in fname
if ".xls" in fname
]
df =pd.concat(excels)
df.to_excel("结果文件.xlsx",index=False)