本内容基于Al Sweigart所著《用python自动化无聊的事情》
原文链接:[用python自动化无聊的事情第七章](https://automatetheboringstuff.com/2e/chapter7/)
本文仅为作者 铃屋琨 学习笔记,非用作商业行为
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
简而言之,就是用‘\d\d\d’的形式来查找字符串中的三个连续数字的方法
Python 中的所有正则表达式函数都在re模块中,所以在使用正则表达式前需要先引用re模块。
// Python 中的所有正则表达式函数都在re模块中
import re
将表示正则表达式的字符串值传递给re.compile() 会返回一个Regex模式对象,我们通过Regex模式对象来表示正则表达式并完成之后的行为
phone_num_Regex = re.compile(r'\d\d\d\d\d\d\d\d\d\d\d')
在这里我们用电话号码为例,众所周知中国电话号码为13位,我们通过r’\d\d\d\d\d\d\d\d\d\d\d’来表示电话号码的正则表达式(书中为美国电话号码形式)
一个正则表达式对象(Regex对象)的search()方法搜索它通过了对正则表达式匹配任何字符串。如果在字符串中找不到正则表达式模式,search()方法将返回None。
string = input()
phone_num_Regex = re.compile(r'\d\d\d\d\d\d\d\d\d\d\d')
my_phonenum=phone_num_Regex.search(string)
print(‘找到电话号码为’+my_phonenum.group())
当我们针对找电话号码问题运用上述代码时可以发现
当输入“我的电话号码为1234567899876”时
得到的输出结果为“找到电话号为123456789876”
这里注意,我们通过re模块的引入,和compile函数构造了Regex对象,即需要的正则表达式,然后通过search()对Regex对象进行查找,得到的是一个Match对象
,在这时我们调用Match对象
的group()
返回了实际匹配出来的值。
当我们使用正则表达式中的括号(见 四 正则表达式的符号 括号),我们将正则表达式分为了几个部分,此时我们可以调用group()函数进行分组表达,例如对上述代码的定义行进行如下的改动:
phone_num_Regex = re.compile(r'(\d\d\d)(\d\d\d\d\d\d\d\d)')
此时我们便得到了包含两个group的正则表达式,可以分别用my_phonenum.group(1)
和my_phonenum.group(2)
表示两个组。
注意1:my_phonenum.group()
表示正则表达式的第一个组。
注意2:group()
函数仅用于一个正则表达式的分组,不能用于多个正则表达式的搜索和表示,搜索所有正则表达式用 findall()函数
(见下方 4 搜索所有正则表达式 findall())。
注意3:group()是针对匹配到的正则表达式进行操作——找到正则表达式中括号地方所指的东西,无论括号在正则表达式的前后。
注意4:如果想一次检索所有组,请使用groups()方法
——注意名称的复数形式。
search()返回第一个在字符串中查找到的正则表达式,而findall()返回每一个查找到的正则表达式。与此同时与search()不同的是,findall()不返回Match对象,而返回的是字符串列表(如果包含group则返回元胞列表)
string = input()
phone_num_Regex = re.compile(r'\d\d\d\d\d\d\d\d\d\d\d')
my_phonenum=phone_num_Regex.findall(string)
print(my_phonenum)
符号 | 意义 | 例子 |
---|---|---|
() | 分组,使用group函数表示 | re.compile(r’((\d\d\d)) (\d\d\d)’) |
| | 代表任何想要匹配的多个表达式之一 | re.compile(r’Bat(man|mobile|copter|bat)’) |
? | 可选匹配 | re.compile(r’Bat(wo)?man’) |
* | 零个或多个匹配 | re.compile(r’Bat(wo)*man’) |
+ | 一个或多个匹配 | re.compile(r’Bat(wo)+man’) |
{} | 特定重复次数 | (Ha){3,5} |
^ | 匹配必须出现在文本的开头 | re.compile(r’^Hello’) |
$ | 匹配必须出现在文本的结尾 | re.compile(r’\d$’) (数字结尾) |
(Ha){3,5}可以匹配字符串’HaHaHaHaHa’中Ha 的三个、四个或五个实例,但“HaHaHaHaHa”的时候返回得到“HaHaHaHaHa”,这是因为:
默认情况下,Python 的正则表达式是贪婪的,这意味着在不明确的情况下,它们将匹配尽可能长的字符串。如在大括号后加?则获得非贪婪性。
速记字符类 | 代表 |
---|---|
\d | 所有数字 |
\D | 任何不是数字的字符 |
\w | 任何字母、数字或下划线字符 |
\W | 任何不是字母、数字或下划线字符 |
\s | 任何空格、制表符或换行符(一般视为匹配空格) |
\S | 任何不是空格、制表符或换行符 |
用中括号来定义字符类
//定义一个元音字母的字符类
vowel_Regex = re.compile(r'[aeiouAEIOU]')
//定义一个包含小写字母、大写字母和数字的字符类
ascii_Regex = re.compile(r'[a-zA-Z0-9])
注意1:字符类[0-5.]将匹配数字0到5和句点,不需要将其写为[0-5.]。
注意2:在字符类的左括号之后放置一个脱字符 ( ^ ),您可以创建一个否定字符类
注意3:我们通过使用句点 . 来表示除换行符以外的所有字符,如:
atRegex = re.compile(r'.at')
通过这个正则表达式我们可以匹配如cat、rat、sat等
注意4:点字符表示“除换行符之外的任何单个字符”,星号表示“前一个字符的零个或多个”,所以我们常用点星来表示一切,如:
nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)')
通过这个正则表达式我们可以匹配姓名
当我们在compile()函数的第二个参数上写明re.I则匹配不会区分大小写。
robocop = re.compile(r'robocop', re.I)
robocop.search('RoboCop')
>>>'RoboCop'
正则表达式是一个寻找字符串中指定字符的良好方式,通过调用正则表达式的相关函数,利用好指定的字符可以实现高效的查找。
最后我将书中联系项目的题目放在这里,有兴趣的读者可以自行实验。
(题目的参考代码在书中有介绍)
假设您有一项在长网页或文档中查找每个电话号码和电子邮件地址的无聊任务。如果您手动滚动页面,最终可能会搜索很长时间。但是,如果您有一个程序可以在剪贴板中搜索电话号码和电子邮件地址的文本,您只需按CTRL- A 选择所有文本,按CTRL- C 将其复制到剪贴板,然后运行您的程序. 它可以仅用它找到的电话号码和电子邮件地址替换剪贴板上的文本。
每当您处理一个新项目时,就很容易直接潜入编写代码。但通常情况下,最好退后一步,考虑更大的图景。我建议首先为您的程序需要做的事情制定一个高级计划。暂时不要考虑实际的代码——您可以稍后再考虑。现在,坚持广泛的笔触。
例如,您的电话和电子邮件地址提取器需要执行以下操作:
1.从剪贴板中获取文本。
2.查找文本中的所有电话号码和电子邮件地址。
3.将它们粘贴到剪贴板上。
现在您可以开始考虑这在代码中如何工作。该代码将需要执行以下操作:
1.使用pyperclip模块复制和粘贴字符串。
2.创建两个正则表达式,一个用于匹配电话号码,另一个用于匹配电子邮件地址。
3.查找两个正则表达式的所有匹配项,而不仅仅是第一个匹配项。
4.将匹配的字符串整齐地格式化为单个字符串以进行粘贴。
5.如果在文本中找不到匹配项,则显示某种消息。
这份清单就像是该项目的路线图。在编写代码时,您可以分别关注这些步骤中的每一个。每个步骤都相当易于管理,并根据您已经知道如何在 Python 中执行的操作来表达。