Python3:正则表达式

正则表达式基本

# 正则表达式
"""
1、正则表达式的定义:
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特殊字符、及这些特定字符的组合,组成一个”规则字符串“,这个”规则字符串“用来表达对字符串的一种过滤逻辑。

正则表达式是对字符串(包括普通字符(类如a-z之间的字母)和特殊字符(成为”元字符“))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一
个”规则字符串“,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,模式描述在搜索文本时要匹配一个或者多个字符串。

正则表达式,又称正则表示式、正规表示式、规则表达式、常规表示法(英文:Regular Expression,在代码中regex、regexp或RE)是计算机科学一种概念。正则表达式使用单个
字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换哪些匹配某个模式的文本。

Regular Expression ”Regular“ 一般被翻译为”正则“、”正规“、”常规“。此处的”Regular“即是”规则“、”规律”的意思 Regular Expression即“描述某种规则的表达式”之意

正则在所有语言中都有的内容

2、正则表达式的作用和特点
给定一个正则表达式和一个字符串,可以达到如下目的
1)给定的字符串是否符合正则表达式的过滤逻辑(成为“匹配”)
2) 可以通过正则表达式,从字符串中获取我们想要的特定部分

正则表达式的特点:
1)灵活性、逻辑性和功能性非常强
2)可以迅速用极简单的方法达到字符串的复杂控制
3)对于刚接触的人比较晦涩难懂

场景:
如何判断一个字符串是手机号?

判断邮箱为163或者126的所有邮件地址
假如你在写一个爬虫,你得到了一个网页的HTML源码,其中有一段

s = "<html><body><h1>hello world</h1></body></html>"
你想要把这个hello world 提取出来,但你这时如果只会python 的字符串处理,那么第一反应可能是
s = "<html><body><h1>hello world</h1></body></html>"
start_index = s.find('<h1>')

python  re模块

\A:表示从字符串的开始处匹配
\Z: 表示从字符串的结束处匹配,如果存在换行,只匹配到换行前的结束字符串
\b: 匹配一个单词边界,也就是指单词和空格间的位置。例如,‘py\b’ 可以匹配”python“中的”py“,但不能匹配”openpyxl“中的”py“
\B: 匹配非单词边界。”py\b“ 可以匹配”openpyxl“ 中的”py“, 但不能匹配”python“ 中的”py“。
\d:匹配任意数字,等价于[0-9].             digit
\D:匹配任意非数字字符,等价于[^\d]         not  digit
\s:匹配任意空白字符,等价于[\t\n\r\f].     space
\S:匹配任意非空白字符,等价于【^\s】.
\w:匹配任意字母数字及下划线,等价于[a-zA-Z0-9_]     word
\W:匹配任意非字母数字及下划线,等价于[^\w]
\\:匹配原意的反斜杠\。

".":用于匹配换行符(\n)之外的字符。  (任意字符除了\n) 注意: . 必须被转义否则会匹配任意字符  建议\.
"^":方括号里边是非; 用于匹配字符串的开始
"$":用于匹配字符串的末尾(末尾如果有换行符\n,就匹配\n前面的那个字符),即行尾
"*" 用于将前面的模式匹配0此或多次(贪婪模式:即尽可能多匹配)
"+" 用于将前面的模式匹配1此或者多次(贪婪模式)
"?" 用于将前面的模式匹配0此或者1次(贪婪模式)
"*?,+?,??" 即上面三种特殊字符的非贪婪模式(尽可能少的匹配)
“{m,n}” 用于将前面的模式匹配m次到n次(贪婪模式),即最小匹配m次,最大匹配n次。
“{m,n}?” 即上面“{m,n}”的非贪婪版本
\\: '\'是转义字符,在特殊字符前面加\,特殊字符就失去了其所代表的含义,比如\+就仅仅代表加号+本身
[]:用于标识一组字符,如果^是第一个字符,则标示的是一个补集。比如[0-9]标示所有的数字,[^0-9]标识除了数字外的字符。
|:比如A|B用于匹配A或者B
(...):用于匹配括号中的模式,可以在字符串中检索或匹配我们所需要的内容。

[] :表示范围  [abc][a-z] [a-z*&]或者的关系   、表示单个字母而不是但单词
|:或者
():#  (qq|163|126)  小括号表示整体返回的或者  qq 或者163 或者126


量词:
*   >=0
+   >=1
?   0,1
{m} 固定几位
{m,}    >=m
{m,n}   m<= x <=n

正则符号:

注意:
  \d  [a-z]  指标是一个字符
   . 必须被转义否则会匹配任意字符  建议\.

Python里数量词默认是贪婪模式(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;
非贪婪则相反,总是尝试匹配尽可能少的字符。

在”*“,”?“,"+" {m,n}后面加?,使贪婪变成非贪婪
"""
# 使用正则表达式验证qq的合法性验证
qq = input("请输入你的QQ号码:")
if len(qq) >= 5 and not qq.startswith("0"):  # qq[0] !='0'
    print("qq号码是合法的")
else:
    print("不合法")

# 正则表达式

import re

message = 'sanduo lily lucy'
pattern = re.compile('lily')  # 匹配失败:none
# pattern = re.compile('sanduo') # 匹配成功:<re.Match object; span=(0, 6), match='sanduo'>
result = pattern.match(message)  # 没有匹配返回空(从头开始匹配)

print(result)

# 正则模块的方法re : match

re_match = re.match("sanduo", message)  # 从头开始匹配,没有就返回None
print(re_match)  # <re.Match object; span=(0, 6), match='sanduo'>

re_search = re.search("lily", message)  # <re.Match object; span=(7, 11), match='lily'>  #匹配的是整个字符串(从头一直找到尾)
print(re_search)
print(re_search.span())  # (7, 11)  span 是匹配的位置;翻译一个位置
print(re_search.groups())  # () 空元组
print(re_search.group())  # 使用group提取匹配的数据

# a2b h6k

msg = 'bckshsaa cinlwn&nel*223jluin8819jhunk21nlini'

result = re.findall('[a-z][0-9]+[a-z]', msg)
print(result)  # ['n8819j', 'k21n']

# 用户名可以是字母或者数字,不能是数字开头,用户长度必须是6位以上['a-zA-Z\[d|a-zA-Z]{5,}']

name1 = '0Asanduo123'
name2 = "SanDUuo123"
name3 = "SanDUuo123#&"  # 必须用$符号结尾
name4 = "123SanDUuo123#&"  # 必须用^符号限制开始
name1_result = re.match("[a-zA-Z][0-9a-zA-Z]{5,}", name1)  # name1_result None
print("name1_result", name1_result)
name2_result = re.match("[a-zA-Z][0-9a-zA-Z]{5,}", name2)  # <re.Match object; span=(0, 10), match='1008001917'>
print("name2_result", name2_result)
name3_result = re.match("[a-zA-Z][0-9a-zA-Z]{5,}$", name3)  # match  $ 限定结尾;name3_result None
print("name3_result", name3_result)
name4_result = re.search("^[a-zA-Z][0-9a-zA-Z_]{5,}$", name4)  # 如果是search:^  限定开始  name4_result None
print("name4_result", name4_result)

name4_result = re.search("^[a-zA-Z]\w{5,}$", name4)  # 如果是search:^  限定开始  name4_result None
print("name4_result", name4_result)

# qq号码校验 5-11位 开头不能是0

qq = "1008001917"
qq_match = re.match("^[1-9][0-9]{4,10}$", qq)

print(qq_match)  # <re.Match object; span=(0, 10), match='1008001917'>

msg = "aa.py ab.txt bbb.py cc.py DD*py"

msg_border = re.findall("py\\b", msg)  # py\\b   等价  r"py\b"
print(msg_border)  # ['py', 'py', 'py', 'py']
msg_border = re.findall(r"\w*\.py\b", msg)  # r不发生转义  . 必须被转义否则会匹配任意字符  建议\.
print(msg_border)  # ['aa.py', 'bbb.py', 'cc.py']

# 手机号码正则

phone = "18700191127"
match_none = re.match(r"^1[35789]\d{9}$", phone)
print("match_none", match_none)  # match_none <re.Match object; span=(0, 11), match='18700191127'>

print("贪婪非贪婪操作".center(20, "*"))

msg = "abc123adrd"
msg_match = re.match(r"[a-z]+\d+", msg)

# 贪婪模式:默认 只要后面有符合条件的,就往后面取
print(msg_match)  # <re.Match object; span=(0, 6), match='abc123'>

msg_match = re.match(r"[a-z]+\d+?", msg)

# 非贪婪模式:将贪婪模式变成非贪婪模式 加 “?”  只要发现就停止了,不会在给后面匹配了
print(msg_match)  # <re.Match object; span=(0, 4), match='abc1'>

path = '<img class="main_img img-hover" data-imgurl="http://t14.baidu.com/it/u=963524666,2960549705&amp;fm=224&amp;app=112&amp;f=JPEG?w=500&amp;h=500" src="http://t14.baidu.com/it/u=963524666,2960549705&amp;fm=224&amp;app=112&amp;f=JPEG?w=500&amp;h=500" style="width: 151px; height: 160px;">'

img_match = re.match(r'<img class="main_img img-hover" data-imgurl=(.+) src=(.+?)"', path)

print(img_match)
print(img_match.groups())
print(img_match.group(1))# http://t14.baidu.com/it/u=963524666,2960549705&amp;fm=224&amp;app=112&amp;f=JPEG?w=500&amp;h=500
print(img_match.group(2)) # http://t14.baidu.com/it/u=963524666,2960549705&amp;fm=224&amp;app=112&amp;f=JPEG?w=500&amp;h=500

# 链接有逗号报错:requests.exceptions.InvalidSchema: No connection adapters were found for
image_url = img_match.group(1)

import requests

response = requests.get("http://bpic.588ku.com/webpage_pic/22/06/29/b5a3b7ea8e66fa74090d7e1269a2b478.jpg")
# response = requests.get(image_url)  # requests.exceptions.InvalidSchema: No connection adapters were found for

print(response)
with open('aa.jpg', 'wb') as write_stream:
    # print(response)
    write_stream.write(response.content)

正则表达式:分组

# 分组匹配
"""
group:()  两种:(number 、name)
    分组:() -->result.group(1) 获取组中的匹配内容   名字匹配
        分组的时候可以结合 |
            phone = "010-12345667"
            match_phone = re.match(r"(\d{3}|\d{4})-(\d{8})$", phone)
            print(match_phone)  # <re.Match object; span=(0, 12), match='010-12345667'>
    不需要引用分组的内容:引用匹配
        msg = "<html><h1>abc</h1></html>"
        result_msg = re.match(r"<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$", msg)
        print(result_msg)  # <re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>
        print(result_msg.group(1))
    引用分组匹配的内容:
        1、number (标签少) \number  引用第number组的内容
            msg = "<html><h1>abc</h1></html>"
            result_msg = re.match(r"<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$", msg)
        2、?P<名字>(标签多)
            s = "<html><body><h1>hello world</h1></body></html>"
            s_match = re.match(r"<(?P<name1>\w+)><(?P<name2>\w+)><(?P<name3>\w+)>(.+)</(?P=name3)></(?P=name2)></(?P=name1)>", s)
            print(s_match)  # <re.Match object; span=(0, 46), match='<html><body><h1>hello world</h1></body></html>'>
            print(s_match.group(1))
    re模块:
        match:从头匹配到尾,只匹配一次
        search:找到第一个就停止查找,并返回:只匹配一次
        findall:查找所有
        sub(正则表达式、需要替换的新内容或者函数、原字符串):替换
        split:字符串中搜索如果遇到 空格 就分割,将分割的类容都保存到列表中
            re_split = re.split(r" ", "java:80 python:70")  # 空格
            print(re_split)  # ['java:80', 'python:70']

            split(pattern,str)-->[]
"""
import re

# 匹配数字0-100

n = "50"

re_match = re.match(r"[1-9]?\d", n)
print(re_match)  # <re.Match object; span=(0, 2), match='50'>

nu = "09"
re_match = re.match(r"[1-9]?\d", nu)
print(re_match)  # <re.Match object; span=(0, 1), match='0'>   有问题

num = "100"
re_match = re.match(r"[1-9]?\d", num)  # <re.Match object; span=(0, 2), match='10'>
print(re_match)

re_match = re.match(r"[1-9]+\d*", num)  # <re.Match object; span=(0, 2), match='10'>
print(re_match)  # <re.Match object; span=(0, 3), match='100'>

# 改进版
new_num = "100"
re_match = re.match(r"[1-9]?\d?$|100$", new_num)  # <re.Match object; span=(0, 3), match='100'>
print(re_match)  # <re.Match object; span=(0, 2), match='10'>

# 验证邮箱163 qq  126

email = "123@qq.com"

match_email = re.match(r"\w+@(qq|163|126).com$", email)  # (qq|163|126)  小括号表示整体返回的或者

print(match_email)  # <re.Match object; span=(0, 10), match='123@qq.com'>

# 邮件名称必须大于5位,小于20位
email = "1006779691@163.com"

match_email = re.match(r"\w{5,20}@(qq|163|126)\.com$", email)  # (qq|163|126)  小括号表示整体返回的或者

print(match_email)  # <re.Match object; span=(0, 18), match='1006779691@163.com'>

print("正则分组操作".center(20, "*"))
# group

# a2b h6k

msg = 'bckshsaa cinlwn&nel*223jluin8819jhunk21nlini'

result = re.search(r"[a-z]\d+[a-z]", msg)  # search只要找到就停下了
# print(result)
print(result.group())  # ['n8819j', 'k21n']

result = re.findall(r"[a-z]\d+[a-z]", msg)  # findall查找字符串中所有
print(result)  # ['n8819j', 'k21n']

result = re.match(r"[a-z]\d+[a-z]", msg)  # search只要找到就停下了
print(result)

# print(result.group())  # ['n8819j', 'k21n']


# qq号码验证5-11位;0不能开头

qq = "1234"
qq = "100799979"
result = re.match(r"^[1-9]\d{4,10}$", qq)  # <re.Match object; span=(0, 9), match='100799979'>
print(result)

# 分组起名:用起名的方式处理  (?P<名字>正则) 引用(?P=名字)
s = "<html><body><h1>hello world</h1></body></html>"

s_match = re.match(r"<(?P<name1>\w+)><(?P<name2>\w+)><(?P<name3>\w+)>(.+)</(?P=name3)></(?P=name2)></(?P=name1)>", s)

print(s_match)  # <re.Match object; span=(0, 46), match='<html><body><h1>hello world</h1></body></html>'>
print(s_match.group(1))
print(s_match.group(2))
print(s_match.group(3))
print(s_match.group(4))
# 使用数字  分组
msg = "<html><h1>abc</h1></html>"
result_msg = re.match(r"<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$", msg)
print(result_msg)  # <re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>
print(result_msg.group(1))
print(result_msg.group(2))
print(result_msg.group(3))

# sub
re_sub = re.sub(r"\d+", "100", "java:80 python:70")
print(re_sub)  # java:100 python:100


# 函数替换
def func(temp):
    nm = temp.group()
    new_nm = int(nm) + 10
    return str(new_nm)


res_sub = re.sub(r"\d+", func, "java:80 python:70")
print(res_sub)  # java:90 python:80

re_split = re.split(r"[,: ]", res_sub)  # 逗号、冒号、空格
print(re_split)  # ['java', '90', 'python', '80']

re_split = re.split(r" ", "java:80 python:70")  # 空格
print(re_split)  # ['java:80', 'python:70']

# 不是以 4、7 结尾的收集号码 11位
phone = "18700191128"
match_phone = re.match(r"1\d{9}[0-35-68-9]$", phone)
print(match_phone)  # <re.Match object; span=(0, 11), match='18700191128'>
print(match_phone.group())  # 18700191128

# 爬虫:分组
phone = "010-12345667"
match_phone = re.match(r"(\d{3}|\d{4})-(\d{8})$", phone)
print(match_phone)  # <re.Match object; span=(0, 12), match='010-12345667'>

# 分别提取
# () 表示分组,groups(1):表示提取第一组的内容,groups(2)表示第二组的内容
print(match_phone.group())  # 默认整体匹配:010-12345667
print(match_phone.group(1))  # 010
print(match_phone.group(2))  # 12345667

# 引用分组 \1
msg = "<html>abc</html>"
msg_match = re.match(r"<([0-9a-zA-Z]+)>(.+)</\1>$", msg)
print(msg_match)  # <re.Match object; span=(0, 16), match='<html>abc</html>'>
print(msg_match.groups())  # ('html', 'abc')
print(msg_match.group(2))  # abc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值