问题:假设你有一个无聊的任务,要在很长的文章中,找出所有的电话号码和邮件地址。如果手动翻页,那可能需要很长时间。若果你有一个程序,可以在剪切板的文本中查找电话号码和email地址,那你只用按下cltr+a全选所有文本,然后拷贝到剪切板上,它会用找到的电话号码和email地址替换掉剪切板上的文本。
目的:
1.从剪切板取得文本
2.找出文本中所有的电话号码
3.将它们粘贴到剪切板
如何做:
1.使用pyperclip模块复制和粘贴字符串
2.创建两个正则表达式,找到所有匹配的内容
3.整理匹配的字符串,放在一个字符串中,用于粘贴
4.如果文本中没有匹配字符串,则返回提示消息
step1:为电话号码创建一个正则表达式
# -*- coding: UTF-8 -*- # author :ray 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) #创建一个正则表达式来匹配email地址 emailRegex = re.compile(r'''( [a-zA-Z0-9._%+-]+ #用户名 @ #@标记 [a-zA-Z0-9.-]+ #域名 (\.[a-zA-Z]{2,4}) #.something )''', 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('Copied to clipboard:') print('\n'.join(matches)) else: print('No phone numbers or emails addresses found.')
/Users/mac/anaconda3/bin/python /Users/mac/PycharmProjects/Mine/reg/phoneAndEmail.py Copied to clipboard: [email protected] [email protected] [email protected] [email protected]
这里电话没有匹配出来,是因为网站上的电话格式修改了。稍后修改下phoneRegex匹配。
现在先回顾一下正则表达式的学习:
在python中使用正则表达式有如下步骤:
1.import re 2.用re.compile()函数创建Regex对象(即re.compile()的返回值为一个Regex对象) 3.对Regex对象使用search()方法,并传入想查询的字符串,返回一个Match对象 3.调用Match对象的group()方法,返回匹配的文本 以"my number is 415-555-4242."为例 欲匹配这个字符串中的电话号码可以使用如下几种正则表达式: 1.numRegex = re.compile(r'\d\d\d-\d\d\d\d-\d\d\d\d')这是最简单也是最傻的方法,刚才写的时候都觉得自己很傻 2.numRegex = re.compile(r'\d{3}-\d{4}-\d{4}')用花括号(大括号)匹配特定次数 3.numRegex = re.compile(r'(\d{3})-(\d{4})-(\d{4})')这里是仅仅是利用括号分组,分组之后可以一次性获取所有的分组 >>> phoneRegex = re.compile(r'(\d{3})-(\d{4})-(\d{4})') >>> phone = phoneRegex.search('my phone numbers is 415-5554-2222') >>> phone.group() '415-5554-2222' >>> phone.groups() ('415', '5554', '2222') 这里也可以将分组中的值赋给数目相同变量 其中用花括号匹配特定次数时,花括号内可以有两个参数,也可以只有一个参数. 如:{a,b}、{a,}、{,b} 分别表示匹配次数为a-b、a-~、0-b 正则表达式的匹配模式: 附:我们知道python的正则表达式的匹配是贪心的,也即当同样两个文本匹配时,它会输出较长的文本 1.用|匹配多个分组:也就是匹配|两侧的表达式均可,但是在返回时会优先输出先匹配的字符 如:nameRegex = re.compile(r'ray|lei')当我们对这个Regex对象使用search方法输入一段字符时, 若文本中包含ray和lei,先出现ray则最后输出为ray,若先出现lei,则输出lei 2.可以用?表示问号前面的表达式是否匹配是可选的,例: nameRegex = re.compile(r'\d-?')也就是说对regex对象使用search方法传入字符串时,数字后有无-是不重要的 3.与2类似的用法,可以用*匹配0次或者多次 4.与2类似的用法,可以用+匹配一次或者多次 5. 点号.可以匹配除换行符外所有的单个字符,它的特殊用法是.*用来匹配所有字符 5.注意:当真正要匹配|、?、*、+、.时可以使用\|,\?\*\+\.来匹配它们 对Regex对象而言它包含以下方法: 1.search(),这个已经讲的很明白了,返回的是被查找字符串中的第一次匹配的文本。 2.findall()它用来查找字符串中的所有匹配。 使用时注意一点: 当表达式中未使用()分组时,返回的结果是一个字符串列表。 而当表达式中使用()分组时,返回的事元组的列表。[(),(),()] 字符分类: \d:匹配0-9的任意数字 \D:匹配任意除0-9的数字 \w:匹配任何字母、数字、下划线的字符(记做word) \W:匹配任何除字母、数字、下划线的字符 \s:匹配空格、制表符、换行符(记做空白字符) \S:匹配除空格、制表符、换行符外的任何字符 当我们建立一个Regex对象时,会写正则表达式,你可以用以上所有介绍过的匹配方式表示你所想匹配的模型, 也可以使用[]定义自己的字符分类,通常在[]左边加上一个插入字符^即^[]表示匹配除[]内的以外的所有字符 在正则表达式的开始处可以使用插入符号^,表示匹配必须发生在被查找文字的开头出,也就是字符串首部要与你的匹配模式相同 同样的,在表达式的最后可以使用美元符$,表示必须以它前面的正则表达式结束。 特殊的当你的正则表达式同时包含^和$时,表明对Regex对象使用search方法时传入的字符串必须满足整个正则表达式 我们在创建Regex对象时,需要向re.compile()方法同时传入第二个参数:re.DOTALL 例如:re.compile(r'.*',re.DOTALL) 当正则表达式指定匹配文本的大小写 当不在乎匹配的字符串的大小写时,可以在建立Regex对象时,向re.compile()中传入第二个参数re.I python中向re.compile()并不允许传入多余两个以上的参数,有必要时,使用|符号.
刚才写完了去洗澡回来发现之前的phoneRegex匹配没有解决。上图看一下它的电话格式是如何
这里修改下phoneRegex正则表达式里的连字符发现文章开头的部分代码错误:先修正如下:
然后此处电话的形式有些看不习惯,原因是在遍历剪切板内容时,findall()方法返回的是包含每个元组内包含五个字符的列表,在循环中打错字符用“_”,导致"".join()方法连接时出现问题。
晚些时间会再写一篇博客记录正则表达式习题的问题。