- 内容提要
- 作者简介
- 技术评审者简介
- 致谢
- 译者序 会编程的人不一样
- 前言
- 本书的读者对象
- 编码规范
- 什么是编程
- 本书简介
- 下载和安装 Python
- 启动 IDLE
- 如何寻求帮助
- 聪明地提出编程问题
- 小结
- 第一部分 Python 编程基础
- 第1章 Python 基础
- 第2章 控制流
- 第3章 函数
- 第4章 列表
- 第5章 字典和结构化数据
- 第6章 字符串操作
- 第二部分 自动化任务
- 第7章 模式匹配与正则表达式
- 第8章 读写文件
- 第9章 组织文件
- 第10章 调试
- 第11章 从 Web 抓取信息
- 第12章 处理 Excel 电子表格
- 第13章 处理 PDF 和 Word 文档
- 第14章 处理 CSV 文件和 JSON 数据
- 第15章 保持时间、计划任务和启动程序
- 第16章 发送电子邮件和短信
- 第17章 操作图像
- 第18章 用 GUI 自动化控制键盘和鼠标
- 附录A 安装第三方模块
- 附录B 运行程序
- 附录C 习题答案
7.15 项目:电话号码和 E-mail 地址提取程序
假设你有一个无聊的任务,要在一篇长的网页或文章中,找出所有电话号码和邮件地址。如果手动翻页,可能需要查找很长时间。如果有一个程序,可以在剪贴板的文本中查找电话号码和E-mail地址,那你就只要按一下Ctrl-A选择所有文本,按下Ctrl-C将它复制到剪贴板,然后运行你的程序。它会用找到的电话号码和E-mail地址,替换掉剪贴板中的文本。
当你开始接手一个新项目时,很容易想要直接开始写代码。但更多的时候,最好是后退一步,考虑更大的图景。我建议先草拟高层次的计划,弄清楚程序需要做什么。暂时不要思考真正的代码,稍后再来考虑。现在,先关注大框架。
例如,你的电话号码和E-mail地址提取程序需要完成以下任务:
· 从剪贴板取得文本。
· 找出文本中所有的电话号码和E-mail地址。
· 将它们粘贴到剪贴板。
现在你可以开始思考,如何用代码来完成工作。代码需要做下面的事情:
· 使用pyperclip模块复制和粘贴字符串。
· 创建两个正则表达式,一个匹配电话号码,另一个匹配E-mail地址。
· 对两个正则表达式,找到所有的匹配,而不只是第一次匹配。
· 将匹配的字符串整理好格式,放在一个字符串中,用于粘贴。
· 如果文本中没有找到匹配,显示某种消息。
这个列表就像项目的路线图。在编写代码时,可以独立地关注其中的每一步。每一步都很好管理。它的表达方式让你知道在Python中如何去做。
第1步:为电话号码创建一个正则表达式
首先,你需要创建一个正则表达式来查找电话号码。创建一个新文件,输入以下代码,保存为phoneAndEmail.py:
#! python3 # phoneAndEmail.py - Finds phone numbers and email addresses on the clipboard. import pyperclip, re phoneRegex = re.compile(r'''( (\d{3}|\(\d{3}\))? # area code (\s|-|\.)? # separator (\d{3}) # first 3 digits (\s|-|\.) # separator (\d{4}) # last 4 digits (\s*(ext|x|ext.)\s*(\d{2,5}))? # extension )''', re.VERBOSE) # TODO: Create email regex. # TODO: Find matches in clipboard text. # TODO: Copy results to the clipboard.
TODO注释仅仅是程序的框架。当编写真正的代码时,它们会被替换掉。
电话号码从一个“可选的”区号开始,所以区号分组跟着一个问号。因为区号可能只是3个数字(即\d{3}),或括号中的3个数字(即(\d{3})),所以应该用管道符号连接这两部分。可以对这部分多行字符串加上正则表达式注释# Area code,帮助你记忆(\d{3}|(\d{3}))?要匹配的是什么。
电话号码分割字符可以是空格(\s)、短横(-)或句点(.),所以这些部分也应该用管道连接。这个正则表达式接下来的几部分很简单:3个数字,接下来是另一个分割符,接下来是4个数字。最后的部分是可选的分机号,包括任意数目的空格,接着ext、x或ext.,再接着2到5位数字。
第2步:为E-mail地址创建一个正则表达式
还需要一个正则表达式来匹配E-mail地址。让你的程序看起来像这样:
#! python3 # phoneAndEmail.py - Finds phone numbers and email addresses on the clipboard. import pyperclip, re phoneRegex = re.compile(r'''( --_snip_-- # Create email regex. emailRegex = re.compile(r'''( ❶ [a-zA-Z0-9._%+-]+ # username ❷ @ # @ symbol ❸ [a-zA-Z0-9.-]+ # domain name (\.[a-zA-Z]{2,4}) # dot-something )''', re.VERBOSE) # TODO: Find matches in clipboard text. # TODO: Copy results to the clipboard.
E-mail地址的用户名部分❶是一个或多个字符,字符可以包括:小写和大写字母、数字、句点、下划线、百分号、加号或短横。可以将所有这些放入一个字符分类:[a-zA-Z0-9._%+-]。
域名和用户名用@符号分割❷,域名❸允许的字符分类要少一些,只允许字母、数字、句点和短横:[a-zA-Z0-9.-]。最后是“dot-com”部分(技术上称为“顶级域名”),它实际上可以是“dot-anything”。它有2到4个字符。
E-mail地址的格式有许多奇怪的规则。这个正则表达式不会匹配所有可能的、有效的E-mail地址,但它会匹配你遇到的大多数典型的电子邮件地址。
第3步:在剪贴板文本中找到所有匹配
既然已经指定了电话号码和电子邮件地址的正则表达式,就可以让 Python的re模块做辛苦的工作,查找剪贴板文本中所有的匹配。pyperclip.paste()函数将取得一个字符串,内容是剪贴板上的文本,findall()正则表达式方法将返回一个元组的列表。
让你的程序看起来像这样:
#! python3 # phoneAndEmail.py - Finds phone numbers and email addresses on the clipboard. import pyperclip, re phoneRegex = re.compile(r'''( --_snip_-- # Find matches in clipboard text. 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]) # TODO: Copy results to the clipboard.
每个匹配对应一个元组,每个元组包含正则表达式中每个分组的字符串。回忆一下,分组0匹配整个正则表达式,所以在元组下标0处的分组,就是你感兴趣的内容。
在❶处可以看到,你将所有的匹配保存在名为matches的列表变量中。它从一个空列表开始,经过几个for循环。对于E-mail地址,你将每次匹配的分组0添加到列表中❸。对于匹配的电话号码,你不想只是添加分组0。虽然程序可以“检测”几种不同形式的电话号码,你希望添加的电话号码是唯一的、标准的格式。phoneNum变量包含一个字符串,它由匹配文本的分组1、3、5和8构成❷。(这些分组是区号、前3个数字、后4个数字和分机号。)
第4步:所有匹配连接成一个字符串,复制到剪贴板
现在,E-mail地址和电话号码已经作为字符串列表放在matches中,你希望将它们复制到剪贴板。pyperclip.copy()函数只接收一个字符串值,而不是字符串的列表,所以你在matches上调用join()方法。
为了更容易看到程序在工作,让我们将所有找到的匹配都输出在终端上。如果没有找到电话号码或E-mail地址,程序应该告诉用户。
让你的程序看起来像这样:
#! python3 # phoneAndEmail.py - Finds phone numbers and email addresses on the clipboard. --_snip_-- for groups in emailRegex.findall(text): matches.append(groups[0]) # Copy results to the clipboard. if len(matches) > 0: pyperclip.copy('\n'.join(matches)) print('Copied to clipboard:') print('\n'.join(matches)) else: print('No phone numbers or email addresses found.')
第5步:运行程序
作为一个例子,打开你的Web浏览器,访问No Starch Press的联系页面http://www.nostarch.com/contactus.htm。按下Ctrl-A选择该页的所有文本,按下Ctrl-C将它复制到剪贴板。运行这个程序,输出看起来像这样:
Copied to clipboard: 800-420-7240 415-863-9900 415-863-9950 info@nostarch.com media@nostarch.com academic@nostarch.com help@nostarch.com
第6步:类似程序的构想
识别文本的模式(并且可能用sub()方法替换它们)有许多不同潜在的应用。
· 寻找网站的URL,它们以http://或https://开始。
· 整理不同日期格式的日期(诸如3/14/2015、03-14-2015和2015/3/14),用唯一的标准格式替代。
· 删除敏感的信息,诸如社会保险号或信用卡号。
· 寻找常见打字错误,诸如单词间的多个空格、不小心重复的单词,或者句子末尾处多个感叹号。它们很烦人!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论