Python正则表达式学习指南

第一次听到 “正则表达式” 这个词的时候,我还以为是什么高深莫测的数学公式,心里直打鼓,觉得肯定特别难学。后来在数据处理的课程上,老师介绍说它是能轻松搞定各种复杂的文本操作,我才鼓起勇气开始探索这个神秘领域。没想到,一番学习下来,我彻底被它的强大魅力征服了!

一、初遇正则表达式:简单示例开启探索之门

学习正则表达式,就像学开车要先熟悉方向盘和油门一样,得从基础示例入手。在 Python 里,通过re模块就能使用正则表达式,它就像是我们打开文本处理宝库的钥匙。

import re
string = '我今年22岁'
result = re.search('\d+', string)
print(result.group())

运行这段代码,屏幕上显示出22。当时我盯着这个结果,又兴奋又好奇。import re是导入正则表达式模块,就像给程序安装了一个强大的插件;string = '我今年22岁'定义了我们要处理的文本;re.search('\d+', string)用search方法在字符串里找东西,\d+就是我们设定的 “搜索目标”。\d表示数字,+表示一个或多个,连起来就是找连续的数字。最后print(result.group())把找到的数字打印出来。这个简单的例子,让我一下子明白了正则表达式的基本运作方式,就像推开了一扇新世界的大门!​

从这个例子能看出来,学习正则表达式主要得掌握两块内容:一个是re模块里各种方法的用法,另一个是正则表达式本身的匹配规则。这就好比学做菜,既要知道锅碗瓢盆怎么用,又要了解食材的搭配和烹饪技巧。接下来,我就深入学习了这两方面的知识。

二、re 模块:常用方法大揭秘

re模块提供了好多实用的方法,每个方法都像是一把独特的工具,在不同的文本处理场景中发挥着关键作用。我把它们整理成表格,方便记忆和对比:

方法

描述

re.match(pattern, string)

从字符串开头开始匹配正则表达式,如果匹配成功就返回匹配对象,失败则返回None

re.search(pattern, string)

在整个字符串里搜索第一个匹配正则表达式的位置,找到就返回匹配对象,找不到返回None

re.findall(pattern, string)

找出字符串里所有匹配的子串,结果以列表形式呈现

re.finditer(pattern, string)

和findall类似,也是找出所有匹配子串,但以迭代器形式返回

re.sub(pattern, repl, string)

把匹配的子串替换成指定内容

re.split(pattern, string)

根据正则表达式分割字符串,返回分割后的列表

刚开始学这些方法的时候,我老是搞混,尤其是match和search。记得有一次做课程作业,需要从一段新闻文本中提取标题,我误用了match方法,怎么都得不到想要的结果。后来仔细检查才发现,因为新闻标题不在文本开头,所以match方法直接返回了None。通过大量练习,我才慢慢摸清它们的脾气。findall方法特别常用,能一下子找出所有符合规则的内容,就像用渔网捕鱼,一网下去收获满满;search方法则像精准的鱼钩,只钓起第一条符合要求的 “鱼” 。

三、元字符和操作符:构建匹配模式的基石

正则表达式里的元字符和操作符,是最让我头疼的部分,感觉它们就像神秘的魔法符号,每个都有独特的含义和用法。

方法

描述

.

匹配除换行符\n之外的任意字符

\d

匹配数字,和[0-9]意思一样

\D

匹配非数字

\w

匹配字母、数字或下划线,等同于[a-zA-Z0-9_]

\W

匹配非字母、数字或下划线

\s

匹配空格、制表符、换行符等空白字符

\S

匹配非空白字符

{n}

让前面的字符恰好出现n次

{n,m}

前面的字符至少出现n次,最多出现m次

^

匹配字符串开头

$

匹配字符串结尾

*

前面的字符出现 0 次或多次

+

前面的字符出现 1 次或多次

?

前面的字符出现 0 次或 1 次

`

`

[]

匹配括号里的任意一个字符

()

捕获匹配的内容

看着这些规则,我头都大了,感觉像在背一本复杂的密码本。但老师说,光看规则没用,得结合实际例子练习。于是,我开始在网上找各种文本数据,反复编写代码测试。慢慢发现这些元字符和操作符组合起来,真的能创造出千变万化的匹配模式,就像用不同的积木块搭建出各种奇妙的建筑!比如在提取邮箱地址时,\w+@\w+\.\w+这个表达式,能精准匹配出所有符合规则的邮箱,这种神奇的效果让我惊叹不已。

四、实战演练:在实践中掌握正则表达式

(1)匹配字符串:精准定位的艺术

match和search方法是我最早练习的。记得第一次用match方法,我想在 “today is a sunny day” 里找 “sunny”,写了re.match(r'sunny', 'today is a sunny day'),结果返回None,当时特别困惑。后来才明白,match是从字符串开头匹配,而 “sunny” 不在开头,所以没找到。这就像在一排书架前找书,match必须从第一个书架开始找,找不到就放弃。

import re
# 使用match方法在字符串开头匹配t开头的单词
result1 = re.match(r't\w+', 'today is a sunny day')
if result1:
    print("match方法匹配成功:", result1.group())
else:
    print("match方法匹配失败")
# 使用search方法在字符串中搜索s开头的单词
result2 = re.search(r's\w+', 'today is a sunny day')
if result2:
    print("search方法搜索成功:", result2.group())
else:
    print("search方法搜索失败")

运行结果是:


search方法就灵活多了,它会在整个字符串里找,就像在整个图书馆里找书,只要有符合条件的就能找到。通过这个练习,我彻底分清了它们的区别。

(2)返回所有匹配结果:一网打尽的畅快

findall方法是我最喜欢的,它能把所有符合条件的内容都找出来。有一次处理一个销售数据文件,里面记录着 “商品 A 价格:199 元,商品 B 价格:299 元” 这样的信息,我想用findall提取所有价格。

import re
text = "商品A价格:199元,商品B价格:299元,商品C价格:399元"
prices = re.findall(r'\d+', text)
print("找到的价格:", prices)

看运行结果:

看着这些被准确提取出来的数据,我特别有成就感,就像把散落的珍珠一颗颗串了起来!在后续的数据分析中,这些提取出的数据直接就能用于计算和统计,大大提高了我的工作效率。

(3)替换字符串:批量修改的神器

1.re.sub方法让我告别了一个个手动替换的痛苦。比如一个留言文档,里面好多 “嘿嘿”,换成 “哈哈”。要是手动改,几百条留言不得改到崩溃?用re.sub就轻松多了:

import re
text = "嘿嘿,这个活动好有趣!嘿嘿,下次我还要参加!"
new_text = re.sub(r'嘿嘿', '哈哈', text)
print("原字符串:", text)
print("替换后的字符串:", new_text)

运行结果:


一下子就把所有 “嘿嘿” 都换成了 “哈哈”,效率超高,简直是 “懒人福音”!更神奇的是,它还能结合元字符进行复杂替换。比如把文档里所有以数字开头的句子,将数字替换成 “序号”,re.sub(r'^\d+', '序号', text)就能轻松实现。

2.在处理文本替换时,我还尝试过更复杂的场景。比如将所有中文数字转换为阿拉伯数字,手动替换几百处数字?这得花整整一天时间!正当我对着屏幕发愁时,突然想到正则表达式的re.sub方法或许能解决问题

import re
text = "一到十分别是:一、二、三、四、五、六、七、八、九、十"
# 定义替换函数
def chinese_to_arabic(match):
    chinese_num = match.group(0)
    num_map = {'一': '1', '二': '2', '三': '3', '四': '4', 
               '五': '5', '六': '6', '七': '7', '八': '8', '九': '9', '十': '10'}
    return num_map.get(chinese_num, chinese_num)
# 使用函数进行替换
new_text = re.sub(r'[一二三四五六七八九十]', chinese_to_arabic, text)
print("替换后:", new_text)

输出结构:

这次经历让我真正体会到正则表达式的 “魔法”。它不仅是机械的文本替换工具,更是能理解复杂逻辑的智能助手

(4)字符串的拆分:灵活分割的技巧

1.re.split方法也很实用。有一次收到一份用不同符号分隔的数据,比如 “苹果;香蕉 | 橙子:葡萄”,普通的split方法就不好用了。用re.split就能轻松搞定:

import re
text = "苹果;香蕉|橙子:葡萄"
fruits = re.split(r'[;|:|]', text)
print("分割结果:", fruits)

运行后得到

不管是分号、竖线还是冒号,都能当作分隔符,特别灵活,就像一把万能剪刀,想怎么剪就怎么剪!在处理 CSV 文件数据时,这个方法也派上了大用场,能准确地将混合分隔符的数据拆分开来。

2.处理 CSV 文件时,我遇到个棘手问题:文件里的数据有逗号,用普通split方法,会把不该分开的内容切断。比如csv_line = '1,"Python,正则表达式",2023' ,用csv_line.split(',') ,"Python,正则表达式" 就被拆开了,这根本不是我想要的!​

我尝试用正则表达式解决,找到r',(?=(?:[^"]*"[^"]*")*[^"]*$)' 这个表达式,可它复杂得像 “天书”。经过反复琢磨教程、写测试代码,我才明白,正向预查(?=…) 能判断逗号是否在引号外,(?:[^"]*"[^"]*")* 则用于检查引号对数,确保只分割引号外的逗号。

import re
# CSV行数据,包含引号内的逗号
csv_line = '1,"Python,正则表达式",2023'
# 使用正则表达式分割,忽略引号内的逗号
fields = re.split(r',(?=(?:[^"]*"[^"]*")*[^"]*$)', csv_line)
print("分割结果:", fields)

输出结果:

看到运行结果['1', '"Python,正则表达式"', '2023'] ,我超兴奋!不过也意识到,这个表达式难写又难维护。后来学习csv模块,才发现有更简单专业的方法。

(5)捕获匹配的内容:精准提取的秘诀

1.“捕获” 功能一开始我理解得很费劲,后来通过一个提取邮箱用户名的例子才搞明白。

import re
text = "我的邮箱是:abc123@example.com"
pattern = r'我的邮箱是:(\w+)@example.com'
result = re.search(pattern, text)
if result:
    print("捕获到的用户名:", result.group(1))

看运行结果:

小括号把我们想要的部分 “圈” 起来,就像用渔网网住特定的鱼,只把我们需要的内容提取出来,特别精准!在用户注册信息处理中,用捕获功能提取用户输入的手机号、邮箱等关键信息,方便又快捷。

2.在实际项目中,我还需要从 URL 中提取参数:

import re
url = "https://example.com/search?keyword=python&page=2"
# 提取所有参数
pattern = r'[?&](\w+)=(\w+)'
params = re.findall(pattern, url)
# 转换为字典
param_dict = {key: value for key, value in params}
print("提取的参数:", param_dict)

输出结果:

这个例子展示了如何使用捕获组提取键值对,并将结果转换为字典结构。

(6)贪婪与非贪婪匹配:匹配策略的选择

贪婪和非贪婪匹配是让我印象最深刻的知识点。第一次遇到的时候,我完全被搞懵了。

import re
text = '<div>content1</div><div>content2</div>'
pattern_greedy = r'<div>.*</div>'
pattern_non_greedy = r'<div>.*?</div>'
result_greedy = re.search(pattern_greedy, text)
result_non_greedy = re.search(pattern_non_greedy, text)
print("贪婪匹配结果:", result_greedy.group())
print("非贪婪匹配结果:", result_non_greedy.group())

运行结果:


贪婪匹配就像个贪吃的小孩,看到东西就想多拿,尽可能匹配最长的字符串;非贪婪匹配则比较 “克制”,拿到满足条件的最短字符串就收手。搞清楚这个区别后,在处理 HTML 标签等数据时,我就能根据需求选择合适的匹配方式了。比如在提取网页中的段落内容时,非贪婪匹配能避免误匹配到其他段落的标签。

(7)“|” 或操作符的作用域:灵活匹配的关键

1.“|” 操作符很有趣,但它的作用域一开始也让我犯错。

import re
text1 = "red pen"
text2 = "blue pen"
pattern1 = r'red|blue pen'
pattern2 = r'(red|blue) pen'
result1_1 = re.match(pattern1, text1)
result1_2 = re.match(pattern1, text2)
result2_1 = re.match(pattern2, text1)
result2_2 = re.match(pattern2, text2)
print("未限定作用域匹配text1结果:", result1_1.group())
print("未限定作用域匹配text2结果:", result1_2.group())
print("限定作用域匹配text1结果:", result2_1.group())
print("限定作用域匹配text2结果:", result2_2.group())

运行输出:


没限定作用域时,它匹配得比较随意;用小括号限定后,就能准确匹配我们想要的内容。这就像给匹配范围画了个圈,让匹配更精准。在处理多条件筛选数据时,合理利用 “|” 操作符及其作用域,能快速筛选出符合要求的数据。

2.在处理多语言文本时,我需要同时匹配中文和英文单词:

import re
text = "Hello 你好 World 世界"
# 匹配英文单词或中文词语
pattern = r'[a-zA-Z]+|[\u4e00-\u9fa5]+'
words = re.findall(pattern, text)
print("匹配结果:", words)

输出结果:

“|” 就像个 “万能连接器”,结合字符集,能把不同规则的匹配条件串联起来。

五、学习感悟:从困难到热爱

         学习正则表达式的过程,就像一场充满挑战的冒险。一开始,面对复杂的元字符和操作符,我常常一头雾水,写代码时也总是出错。记得有一次做一个网页爬虫项目,需要提取网页中的所有链接,因为对正则表达式掌握不熟练,调试了整整两天才成功。但随着不断练习,从简单的匹配数字,到复杂的网页数据提取,我逐渐掌握了其中的规律。每解决一个难题,每成功处理一段文本,都让我充满成就感。​

        现在,我已经能熟练运用正则表达式处理很多实际问题了。在做课程作业、处理实验数据时,它成了我的得力助手。甚至在日常生活中,比如整理电脑里的文件命名,我也会用正则表达式批量修改文件名。我也明白了,学习新技术不能害怕困难,只要多实践、多思考,就能攻克难关。正则表达式的世界还有很多奥秘等待我去探索,我相信,随着学习的深入,我还能发现它更多的强大功能!

作者:黄柳丽

物联沃分享整理
物联沃-IOTWORD物联网 » Python正则表达式学习指南

发表回复