Python基础之正则表达式

Python基础之正则表达式

  • 一:正则表达式
  • 二:正则常用匹配规则
    • 2.1 re.match()
    • 2.2 re.search()
    • 2.3 re.findall()
    • 2.4 re.sub()
    • 2.5 re.split()
  • 三:贪婪和非贪婪
  • 四:小案例

一:正则表达式

Python基础之正则表达式_第1张图片
Python基础之正则表达式_第2张图片
Python基础之正则表达式_第3张图片
Python基础之正则表达式_第4张图片

二:正则常用匹配规则

2.1 re.match()

re.match(正则表达式,要匹配的字符串,flags)
# match从头开始匹配
# re.match默认配置以xxx开头的字符串,所以正则中的^符号可省略不写
# 如果上一步匹配到数据的话,可以使用group方法来提取数据
# flags是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

实例1:匹配某个字符

import re
text = 'hello'
ret = re.match('he', text)
print(ret)				# 如果没有匹配字符,这里返回None
print(ret.group())		# 返回匹配的结果;如果没有匹配字符,这里会抛异常
# 
# he

实例2:点匹配任意一个字符

text = 'hello'
ret = re.match('.', text)
print(ret.group())			# h

注意:点不能匹配换行符
实例3:\d匹配任意数字

text = '1231564hello'
ret = re.match('\d', text)
print(ret.group())			# 1

实例4:\D匹配任意非数字

text = '+hello'
ret = re.match('\D', text)
print(ret.group())

实例5:\s匹配空白字符

# \n, \t, \r及空格
text = '\thello'
ret = re.match('\s', text)
print(ret.group())

实例6:判断列表中元素是否符合变量规范

import re
def main():
    names = ["age", "_age", "1age", "age1", "a_age", "age_1_", "age!", "a#123"]
    for i in names:
        ret = re.match(r"[a-zA-Z_]\w*$", i)     # match默认以^匹配开头,所以^符号可以不写
        if ret:
            print('变量名:%s 符合要求;通过正则匹配出的数据是:%s' % (i, ret.group()))
        else:
            print('变量名:%s 不符合要求' % i)
if __name__ == '__main__':
    main()

实例7:re.match()取分组数据

import re
def main():
    email = input('Please input a email: ')
    ret = re.match(r"[a-zA-Z0-9_]{4,20}@(163|126)\.com$", email)
    print(ret.group())        # 取得匹配到的值
    print(ret.group(1))       # 取得第一个分组(上面括号里的数据)数据
    # 如果正则中只有一个分组,而ret.group(2)取数据会报IndexError: no such group异常
    if ret:
        print('OK')
    else:
        print('Not email')
if __name__ == '__main__':
    main()

2.2 re.search()

re.search函数会在字符串内查找模式匹配,只要找到第一个匹配然后返回,如果字符串没有匹配,则返回None。

ret = re.search(r"\d+", "阅读次数为 9999;点赞次数为 87878")
print(ret.group())    # 9999

2.3 re.findall()

findall(pattern, string, flags=0)
# 返回string中所有与pattern相匹配的全部字串,返回形式为列表
ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)
# ['9999', '7890', '12345']
titles = re.findall(r'.*(.*)', text, re.DOTALL)
# .不匹配\n,后面加上re.DOTALL,表示.也要匹配\n

re.findall()在匹配时分组与不分组的区别

import re
string="abcdefg  acbdgef  abcdgfe  cadbgfe"

#带括号与不带括号的区别
#不带括号
regex=re.compile("((\w+)\s+\w+)")
print(regex.findall(string))
#输出:[('abcdefg  acbdgef', 'abcdefg'), ('abcdgfe  cadbgfe', 'abcdgfe')]

regex1=re.compile("(\w+)\s+\w+")
print(regex1.findall(string))
#输出:['abcdefg', 'abcdgfe']

regex2=re.compile("\w+\s+\w+")
print(regex2.findall(string))
#输出:['abcdefg  acbdgef', 'abcdgfe  cadbgfe']

第一个 regex 中是带有2个括号的,我们可以看到其输出是一个list 中包含2个 tuple
第二个 regex 中带有1个括号,其输出的内容就是括号匹配到的内容,而不是整个表达式所匹配到的结果。
第三个 regex 中不带有括号,其输出的内容就是整个表达式所匹配到的内容。
结论:findall()返回的是括号所匹配到的结果(如regex1),多个括号就会返回多个括号分别匹配到的结果(如regex),如果没有括号就返回就返回整条语句所匹配到的结果(如regex2)。所以在提取数据的时候就需要注意这个坑。

2.4 re.sub()

将匹配到的数据进行替换

re.sub(pattern, repl, string, count=0, flags=0)
# 第一个参数pattern:就是正则式字符串或者正则式对象 
# 第二个参数repl:就是要用什么东西去替换pattern匹配到的字符串(这里也可以是一个函数)
# 第三个参数string:就是对哪个字符串进行匹配与替换 
# 第四个参数count:就是只替换前几个,如果是0则全部都替换

re.sub()简单使用:

ret = re.sub(r"\d+", '100', 'python = 666, c++ = 1024')
print(ret)
# python = 100, c++ = 100

re.sub()使用函数:

def add(temp):
    strNum = temp.group()
    num = int(strNum) + 1
    return str(num)
ret = re.sub(r"\d+", add, "python = 666")
print(ret)
# python = 667

2.5 re.split()

根据匹配进行切割字符串,并返回一个列表

re.split()简单使用

ret = re.split(r":| ","info:xiaoZhang 33 shandong")    # 以冒号或者空格切割,也可以使用[: ]
print(ret)
# ['info', 'xiaoZhang', '33', 'shandong']

使用括号捕获分组,默认保留分割符

ret = re.split(r"([:])","info:xiaoZhang 33 shandong")
print(ret)
# ['info', ':', 'xiaoZhang 33 shandong']

不想保留分隔符,以(?:…)的形式指定

ret = re.split(r"(?:[:])","info:xiaoZhang 33 shandong")
print(ret)
# ['info', 'xiaoZhang 33 shandong']

re.compile写法:

import re
one = 'adkfjklsdjflksd'
pattern = re.compile('s')
result = pattern.split(one)
print(result)		# ['adkfjkl', 'djflk', 'd']

三:贪婪和非贪婪

Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
非贪婪则相反,总是尝试匹配尽可能少的字符。
在 “*” , “?” , “+” , “{m,n}” 后面加上?,使贪婪变成非贪婪。

>>> s="This is a number 234-235-22-423"
>>> r=re.match(".+(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'4-235-22-423'
>>> r=re.match(".+?(\d+-\d+-\d+-\d+)",s)
>>> r.group(1)
'234-235-22-423'

正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在我们上面的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的大部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。

解决方式:非贪婪操作符“?”,这个操作符可以用在"*","+","?"的后面,要求正则匹配的越少越好。

>>> re.match(r"aa(\d+)","aa2343ddd").group(1)
'2343'
>>> re.match(r"aa(\d+?)","aa2343ddd").group(1)
'2'
>>> re.match(r"aa(\d+)ddd","aa2343ddd").group(1) 
'2343'
>>> re.match(r"aa(\d+?)ddd","aa2343ddd").group(1)
'2343'

四:小案例

1:python爬虫抓取网页文章

import re
import requests
def parse_page(url):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    response = requests.get(url, headers=headers)
    text = response.content.decode()
    titles = re.findall(r'(.*)', text)
    befrom = re.findall(r'

(.*)', text) author = re.findall(r'

.*(.*)

'
, text) contents = re.findall(r'
(.*?)
'
, text, re.DOTALL) contents = [re.sub(r'<.*?>', '', content).strip() for content in contents] a = [{'title': titles[i], 'befrom': befrom[i], 'author': author[i], 'content': contents[i]} for i in range(len(titles))] print(a) def main(): url = 'https://www.gushiwen.org/default_1.aspx' parse_page(url) if __name__ == '__main__': main()

2:匹配中文字符

import re
one = 'adq我kfjkl是sdj谁flksd'
pattern = re.compile('[\u4e00-\u9fa5]')		# Python中匹配中文字符的unicode范围
result = pattern.findall(one)
print(result)	# ['我', '是', '谁']

你可能感兴趣的:(python)