Python进阶笔记(1):正则表达式

简介: Python进阶笔记(1):正则表达式

正则表达式


需要导入:import re


1. 匹配符


常用普通字符的含义见下表


普通字符 含义
\W 匹配非数字、字母、下划线、汉字
\w 匹配数字、字母、下划线、汉字
\S 匹配任意非空白字符
\s 匹配任意空白字符
\D 匹配非数字
\d 匹配数字


常用元字符的含义见下表


元字符 含义
. 匹配任意字符(除换行符\r,\n)
^ 匹配字符串的开始位置
$ 匹配字符串的结束位置
* 匹配该元字符的前一个字符任意出现次数(包括0次)
匹配该元字符的前一个字符0次或1次
\ 转义字符,其后的一个元字符失去特殊含义,匹配字符本身
() ()中的表达式称为一个组,组匹配到的字符能被取出
[] 字符集,范围内的所有字符都能被匹配
| 将匹配条件进行逻辑或运算
[abc] 匹配括号内任意字符
[^abc] 匹配非括号内任意字符


2. findall()


使用re模块里面的findall()函数进行查找匹配,返回一个列表。


2.1 \w和\W


import re
str1 = '123Qwe!_@#你我他'
print(re.findall('\w', str1))    # 匹配数字、字母、下划线、汉字
print(re.findall('\W', str1))    # 匹配非数字、字母、下划线、汉字


['1', '2', '3', 'Q', 'w', 'e', '_', '你', '我', '他']
['!', '@', '#']


2.2 \s和\S


import re
str2 = "123Qwe!_@#你我他\t \n\r"
print(re.findall('\s', str2))   # 匹配任意空白字符,如空格、换行符\r
print(re.findall('\S', str2))   # 匹配任意非空白字符


['\t', ' ', '\n', '\r']
['1', '2', '3', 'Q', 'w', 'e', '!', '_', '@', '#', '你', '我', '他']


2.3 \d和\D


import re
str3 = "123Qwe!_@#你我他\t \n\r"
print(re.findall('\d', str3))  # 匹配数字
print(re.findall('\D', str3))  # 匹配非数字


['1', '2', '3']
['Q', 'w', 'e', '!', '_', '@', '#', '你', '我', '他', '\t', ' ', '\n', '\r']


2.4 ^和$


import re
str4 = '你好吗,我很好'
print(re.findall('^你好', str4))  # 匹配字符串的开始的 你好
str5 = '我很好,你好'
print(re.findall('你好$', str5))  # 匹配字符串的结束的 你好 


['你好']
['你好']


2.5 . * ?


import re
str6 = 'abcaaabb'
print(re.findall('a.b', str6))  # 匹配任意一个字符(除换行符\r,\n)
print(re.findall('a?b', str6))  # 匹配字符a0次或1次
print(re.findall('a*b', str6))  # 匹配字符a任意次数(包括0次)
print(re.findall('a.*b', str6)) # 匹配任意字符任意次数 (贪婪匹配)    能匹配多长就多长
print(re.findall('a.*?b', str6))# 匹配任意字符任意次数 (非贪婪匹配)  能匹配多短就多短


['aab']
['ab', 'ab', 'b']
['ab', 'aaab', 'b']
['abcaaabb']
['ab', 'aaab']


2.6 \


import re
str7 = '\t123456'
print(re.findall('t', str7))   # 匹配不到字符t,因为\t有特殊含义,是一个先整体
str8 = '\\t123456' 
print(re.findall('t', str8))   # 使用转义字符后,\t变为无特殊含义的普通字符,能匹配到字符t
str9 = r'\t123456'
print(re.findall('t', str9))   # 在字符串前加r也可以对字符串进行转义


[]
['t']
['t']


2.7 []


import re
str10 = 'aab abb acb azb a1b'
print(re.findall('a[a-z]b', str10))   # 只要中间的字符在字母a~z之间就能匹配到
print(re.findall('a[0-9]b', str10))   # 只要中间的字符在数字0~9之间就能匹配到
print(re.findall('a[ac1]b', str10))   # 只要中间的字符是[ac1]的成员就能匹配到


['aab', 'abb', 'acb', 'azb']
['a1b']
['aab', 'acb', 'a1b']


2.8 ()


import re
str11 = '123qwer'
print(re.findall('(\w+)q(\w+)', str11))  # \w+ 代表匹配一个或多个数字、字母、下划线、汉字


[('123', 'wer')]


2.9 |


import re
str12 = '你好,女士们先生们,大家好好学习呀'
print(re.findall('女士|先生', str12))  # 匹配  先生  或 女士


['女士', '先生']


3. search()


3.1 匹配电话


实例:查找电话


def isPhoneNumber(text):
    """查找\d\d\d-\d\d\d-\d\d\d\d类型的电话的函数 非正则版"""
    if len(text) != 12:
        return False
    for i in range(0,3):
        if not text[i].isdecimal():
            return False
    if text[3] != '-':
        return False
    for i in range(4,7):
        if not text[i].isdecimal():
            return False
    if text[7] != '-':
        return False
    for i in range(8,12):
        if not text[i].isdecimal():
            return False
    return True
message = "Call me at 415-555-1011 tomorrow. 415-555-9999 is my office"
for i in range(len(message)):
    chunk = message[i:i+12]
    if isPhoneNumber(chunk):
        print("Phone number found: " + chunk)
print("Done")


Phone number found: 415-555-1011
Phone number found: 415-555-9999
Done


实例:用正则表达式查找电话号


import re
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search("My number is 415-555-4242.")
print("Phone number found: " + mo.group())


Phone number found: 415-555-4242


正则表达式使用步骤总结:


  1. import re导入正则表达式模块


  1. re.compile()函数创建一个Regex对象(记得使用原始字符串)


  1. 向Regex对象的search()方法传入想查找的字符串。它返回一个Match对象


  1. 调用Match对象的group()方法,返回实际匹配文本的字符串


3.2 利用括号分组


import re
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phoneNumRegex.search("My number is 415-555-4242.")
print(mo.group())
print(mo.group(1)) 
print(mo.group(2))
print(mo.groups())   # 获取所有的分组
areaCode, mainNumber = mo.groups()
print(areaCode, mainNumber)


415-555-4242
415
555-4242
('415', '555-4242')
415 555-4242


3.3 用管道匹配多个分组


字符|称为”管道“,希望匹配许多表达式中的一个,就用它。


第一次出现的匹配文本,将作为Match对象返回。


heroRegex = re.compile(r'Batman|Tina Fey')
mo1 = heroRegex.search('Batman and Tina Fey.')
print(mo1.group())   # 查找第一次出现的   findall()则是查找所有
mo2 = heroRegex.search("Tina Fey and Batman.")
print(mo2.group())


Batman
Tina Fey



batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = batRegex.search('Batmobile lost a wheel')
print(mo.group())
print(mo.group(1))


Batmobile
mobile


3.4 用问号实现可选匹配


batRegex = re.compile(r'Bat(wo)?man')
mo1 = batRegex.search('The Adventures of Batman')
print(mo1.group())
mo2 = batRegex.search('The Adventures of Batwoman')
print(mo2.group())


Batman
Batwoman


例2


phoneRegex = re.compile(r'(\d\d\d-)?\d\d\d-\d\d\d\d')
mo1 = phoneRegex.search('My number is 415-555-4242')
print(mo1.group())
mo2 = phoneRegex.search('My number is 555-4242')
print(mo2.group())


415-555-4242
555-4242


3.5 用星号匹配零次或多次


batRegex = re.compile(r'Bat(wo)*man')
mo1 = batRegex.search('The Adventures of Batman')
print(mo1.group())
mo2 = batRegex.search('The Adventures of Batwoman')
print(mo2.group())
mo3 = batRegex.search('The Adventures of Batwowowowoman')
print(mo3.group())


Batman
Batwoman
Batwowowowoman


3.6 用花括号匹配待定次数


(Ha){3}将匹配字符串HaHaHa
(Ha){3,5}将匹配字符串HaHaHa | HaHaHaHa | HaHaHaHaHa
(Ha){3,}匹配3次及以上
(Ha){,5}匹配0到5次



haRegex = re.compile(r'(Ha){3}')
mo1 = haRegex.search('HaHaHa')
print(mo1.group())
mo2 = haRegex.search('Ha')
print(mo2 == None)  # 因为(Ha){3}匹配HaHaHa,不匹配Ha,所以返回None


HaHaHa
True


3.7 贪心和非贪心匹配


# 贪心
greedyHaRegex = re.compile(r'(Ha){3,5}')
mo1 = greedyHaRegex.search('HaHaHaHaHa')
print(mo1)
# 非贪心
greedyHaRegex = re.compile(r'(Ha){3,5}?')
mo1 = greedyHaRegex.search('HaHaHaHaHa')
print(mo1)


<re.Match object; span=(0, 10), match='HaHaHaHaHa'>
<re.Match object; span=(0, 6), match='HaHaHa'>


3.8 练习


例:search和findall的区别


phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('Cell: 415-555-9999 Work: 212-555-0000')
print(mo.group())
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
print(phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000'))
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
print(phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000'))


415-555-9999
['415-555-9999', '212-555-0000']
[('415', '555', '9999'), ('212', '555', '0000')]


例:匹配元音字符


  • [abc]:匹配括号内任意字符


  • [^abc]:匹配不再括号内的任意字符


# 匹配所有元音字符
voweRgegx = re.compile(r'[aeiouAEIOU]')
print(voweRgegx.findall('RoboCop eats baby food. BABY FOOD.'))
# 匹配所有非元音字符
consonantRgegx = re.compile(r'[^aeiouAEIOU]')
print(consonantRgegx.findall('RoboCop eats baby food. BABY FOOD.'))


例:插入字符


beginWithHello = re.compile(r'^Hello')
print(beginWithHello.search('Hello world!'))
print(beginWithHello.search('He said hello.') == None)


<re.Match object; span=(0, 5), match='Hello'>
True


例:美元字符


endWithNumber = re.compile(r'\d$')
print(endWithNumber.search('Your number is 42'))
print(endWithNumber.search("Your number is forty two") == None)


<re.Match object; span=(16, 17), match='2'>
True


例:匹配以字符开始字符结束的


wholeStringIsNum = re.compile(r'^\d+$')
print(wholeStringIsNum.search('123456789'))
print(wholeStringIsNum.search('12345xyz678') == None)
print(wholeStringIsNum.search('123 456789') == None)


<re.Match object; span=(0, 9), match='123456789'>
True
True


例:通配字符


atRegex = re.compile(r'.at')
print(atRegex.findall('The cat in the hat sat on the flat mat.'))


['cat', 'hat', 'sat', 'lat', 'mat']


例:用点-星匹配所有字符


nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)')
mo = nameRegex.search("First Name: A1 Last Name: Sweigart")
print(mo.group(1))
print(mo.group(2))


A1
Sweigart


例:点-星的贪心和非贪心模式


# 非贪心
nongreedyRegex = re.compile(r'<.*?>')
print(nongreedyRegex.search('<To serve man> for dinner.>'))
# 贪心
greedyRegex = re.compile(r'<.*>')
print(greedyRegex.search('<To serve man> for dinner.>'))


<re.Match object; span=(0, 14), match='<To serve man>'>
<re.Match object; span=(0, 27), match='<To serve man> for dinner.>'>


例:用句点字符匹配换行


# 正常情况不匹配换行符
noNewlineRegex = re.compile('.*')
print(noNewlineRegex.search("Serve the public trust.\nProtect the innocent.\nUphold the law.").group())
# 添加第二个参数,匹配换行符
NewlineRegex = re.compile('.*', re.DOTALL)
print(NewlineRegex.search("aaa.\nbbb.").group())


Serve the public trust.
aaa.
bbb.


例:匹配不区分大小写


# 传入第二个参数,匹配不区分大小写
robocop = re.compile(r'robocop', re.I)
print(robocop.search('RoboCop is part manchine, all cop.').group())
print(robocop.search('ROBOcop is part manchine, all cop.').group())


RoboCop
ROBOcop


例:用sub()方法替换字符串


namesRegex = re.compile(r'Agent \w+')
print(namesRegex.sub("CENSORED", "Agent Alice gave the secret documents to Agent Bob."))


CENSORED gave the secret documents to CENSORED.


agentNamesRegex = re.compile(r'Agent (\w)\w*')
print(agentNamesRegex.sub(r'\1****', "Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent."))


A**** told C**** that E**** knew B**** was a double agent.


3.9 实践:匹配电话号码和E-mail地址


import pyperclip, re
phoneRegex = re.compile(r'''(
        (\d{3}|\(\d{3}\))?
        (\s|-|\.)?
        (\d{3})
        (\s|-|\.)
        (\d{4})
        (\s*(ext|x|ext\.)\s*(\d{2,5}))?
        )''', re.VERBOSE)
emailRegex = re.compile(r'''(
        [a-zA-Z0-9._%=-]+
        @
        [a-zA-Z0-9.-]+
        (\.[a-zA-Z]{2,4})
        )''', re.VERBOSE)
text = str(pyperclip.paste())   # 读取剪切板
matches = []
for groups in phoneRegex.findall(text):
    phoneNum = '-'.join([groups[1], groups[3], groups[5]])  # 拼接电话
    if groups[8] != '':
        phoneNum += ' x' + groups[8]
    matches.append(phoneNum)
for groups in emailRegex.findall(text):
    matches.append(groups[0])
if len(matches) > 0:
    pyperclip.copy('\n'.join(matches))
    print('找到以下电话号码和电子邮箱::')
    print('\n'.join(matches))
else:
    print("未发现电话号码和电子邮箱!")


目录
相关文章
|
4天前
|
机器学习/深度学习 数据采集 算法
Python编程语言进阶学习:深入探索与高级应用
【7月更文挑战第23天】Python的进阶学习是一个不断探索和实践的过程。通过深入学习高级数据结构、面向对象编程、并发编程、性能优化以及在实际项目中的应用,你将能够更加熟练地运用Python解决复杂问题,并在编程道路上走得更远。记住,理论知识只是基础,真正的成长来自于不断的实践和反思。
|
1天前
|
网络协议 Python
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
【7月更文挑战第26天】在网络的数字宇宙中,Python Socket编程是开启网络世界大门的钥匙。本指南将引领你从基础到实战,成为网络世界的建筑师。
6 2
|
2天前
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
【7月更文挑战第25天】在网络应用蓬勃发展的数字时代,Python凭借其简洁的语法和强大的库支持成为开发高效应用的首选。本文通过实时聊天室案例,介绍了Python Socket编程的基础与进阶技巧,包括服务器与客户端的建立、数据交换等基础篇内容,以及使用多线程和异步IO提升性能的进阶篇。基础示例展示了服务器端监听连接请求、接收转发消息,客户端连接服务器并收发消息的过程。进阶部分讨论了如何利用Python的`threading`模块和`asyncio`库来处理多客户端连接,提高应用的并发处理能力和响应速度。掌握这些技能,能使开发者在网络编程领域更加游刃有余,构建出高性能的应用程序。
10 3
|
1天前
|
SQL 安全 Go
SQL注入不可怕,XSS也不难防!Python Web安全进阶教程,让你安心做开发!
【7月更文挑战第26天】在 Web 开发中, SQL 注入与 XSS 攻击常令人担忧, 但掌握正确防御策略可化解风险. 对抗 SQL 注入的核心是避免直接拼接用户输入至 SQL 语句. 使用 Python 的参数化查询 (如 sqlite3 库) 和 ORM 框架 (如 Django, SQLAlchemy) 可有效防范. 防范 XSS 攻击需严格过滤及转义用户输入. 利用 Django 模板引擎自动转义功能, 或手动转义及设置内容安全策略 (CSP) 来增强防护. 掌握这些技巧, 让你在 Python Web 开发中更加安心. 安全是个持续学习的过程, 不断提升才能有效保护应用.
7 1
|
15天前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
43 4
|
17天前
|
算法 Python
Python算法高手进阶指南:分治法、贪心算法、动态规划,掌握它们,算法难题迎刃而解!
【7月更文挑战第10天】探索Python算法的精华:分治法(如归并排序)、贪心策略(如找零钱问题)和动态规划(解复杂问题)。通过示例代码揭示它们如何优化问题解决,提升编程技能。掌握这些策略,攀登技术巅峰。
|
2天前
|
网络协议 开发者 Python
颠覆传统!Python Socket编程新思维,基础与进阶并重,打造卓越网络能力!
【7月更文挑战第25天】在数字时代,网络通信至关重要,Python的Socket编程简化了这一复杂领域,使初学者也能轻松上手。通过Python的`socket`模块,我们能快速搭建服务器与客户端,实现数据交换。示例代码展示了如何创建、绑定及监听Socket,以及收发消息。掌握基础后,可利用asyncio库探索异步编程,提升通信效率,处理多连接。Python的Socket编程,结合传统与现代技术,助力开发者在网络通信领域取得非凡成就。
|
6天前
|
存储 算法 搜索推荐
Python进阶必备:字典树Trie与后缀树Suffix Array,效率提升的神器!
【7月更文挑战第21天】Python进阶:Trie树实现自动补全,后缀数组解决最长重复子串。Trie树优化前缀搜索,适用于自动补全系统,如文本编辑器中的`autocomplete`功能。后缀数组,非树但高效处理字符串后缀,与LCP数组配合找到最长重复子串。两者提升字符串处理效率,是编程利器。学习并运用这些数据结构可增强程序性能。**
13 0
|
6天前
|
前端开发 开发者 Python
从零到一:Python Web框架中的模板引擎入门与进阶
【7月更文挑战第20天】模板引擎如Jinja2在Python Web开发中连接后端与前端,提高代码可读性和协作效率。Flask默认集成Jinja2,提供条件语句、循环、宏和模板继承等功能。例如,创建一个简单Flask应用,渲染&quot;Hello, World!&quot;,并展示如何使用条件语句和循环处理数据。通过宏定义重用代码,模板继承实现页面结构共享。学习模板引擎能提升开发效率和项目质量。
17 0
|
8天前
|
SQL 前端开发 数据库
Python Web开发进阶之路:从模板引擎到ORM的全面掌握
【7月更文挑战第19天】在Python Web开发中,提升技能的关键是理解和运用模板引擎(如Jinja2)与ORM技术。模板引擎,如在Flask中使用的Jinja2,使前端HTML与后端逻辑分离,便于维护。例如,通过路由函数`show_posts()`和`render_template()`呈现文章列表模板,用Jinja2的`for`循环展示内容。ORM,如SQLAlchemy,提供Pythonic的数据库操作,将表映射为类,SQL转化为方法调用。在博客系统中,定义Post模型并与数据库交互,展示了ORM简化数据管理的优势。通过实践这些工具,开发者能更好地驾驭复杂的Web项目。
18 0