假设你有一个无聊的任务, 要在一篇长的网页或文章中, 找出所有电话号码和
邮件地址。如果手动翻页, 可能需要查找很长时间。如果有一个程序, 可以在剪贴
板的文本中查找电话号码和 E-mail 地址, 那你就只要按一下 Ctrl-A 选择所有文本,
按下 Ctrl-C 将它复制到剪贴板,然后运行你的程序。它会用找到的电话号码和 E-mail
地址, 替换掉剪贴板中的文本。
当你开始接手一个新项目时, 很容易想要直接开始写代码。但更多的时候, 最
好是后退一步, 考虑更大的图景。我建议先草拟高层次的计划, 弄清楚程序需要做
什么。暂时不要思考真正的代码, 稍后再来考虑。现在,先关注大框架。
例如, 你的电话号码和 E-mail 地址提取程序需要完成以下任务:
从剪贴板取得文本。
找出文本中所有的电话号码和 E-mail 地址。
将它们粘贴到剪贴板。
现在你可以开始思考, 如何用代码来完成工作。代码需要做下面的事情:
使用 pyperclip 模块复制和粘贴字符串。
创建两个正则表达式,一个匹配电话号码,另一个匹配 E-mail 地址。
对两个正则表达式,找到所有的匹配,而不只是第一次匹配。
将匹配的字符串整理好格式,放在一个字符串中,用于粘贴。
如果文本中没有找到匹配,显示某种消息。
这个列表就像项目的路线图。在编写代码时, 可以独立地关注其中的每一步。
每一步都很好管理。 它的表达方式让你知道在 Python 中如何去做。
#! 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.
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.
# 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.
# 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.')
copy的文档随便从进了一个网址 全选复制,运行程序之后就得到了下面这些结果:
Copied to clipboard:
1067547753@qq.com
2531838911@qq.com
799418861@qq.com
984517363@qq.com
897975405@qq.com
897975405@qq.com
1578110080@qq.com
994771229@qq.com
1181594943@qq.com
2369973779@qq.com
846201599@qq.com
1752898210@qq.com
465064341@qq.com
习题
1.创建 Regex 对象的函数是什么?
2.在创建 Regex 对象时,为什么常用原始字符串?
3. search()方法返回什么?
4.通过 Match 对象,如何得到匹配该模式的实际字符串?
5.用 r'(\d\d\d)-(\d\d\d-\d\d\d\d)'创建的正则表达式中,分组 0 表示什么?分组 1
呢?分组 2 呢?
6.括号和句点在正则表达式语法中有特殊的含义。如何指定正则表达式匹配
真正的括号和句点字符?
7. findall()方法返回一个字符串的列表,或字符串元组的列表。是什么决定它
提供哪种返回?
8.在正则表达式中, |字符表示什么意思?
9.在正则表达式中, ?字符有哪两种含义?
10.在正则表达式中, +和*字符之间的区别是什么?
11.在正则表达式中, {3}和{3,5}之间的区别是什么?
12.在正则表达式中, \d、 \w 和\s 缩写字符类是什么意思?
13.在正则表达式中, \D、 \W 和\S 缩写字符类是什么意思?
14.如何让正则表达式不区分大小写?
15.字符.通常匹配什么?如果 re.DOTALL 作为第二个参数传递给 re.compile(),
它会匹配什么?
16. .*和*?之间的区别是什么?
17.匹配所有数字和小写字母的字符分类语法是什么?
18.如果 numRegex = re.compile(r'\d+'),那么 numRegex.sub('X', '12 drummers, 11
pipers, five rings, 3 hens')返回什么?
19.将 re.VERBOSE 作为第二个参数传递给 re.compile(),让你能做什么?
20. 如何写一个正则表达式, 匹配每 3 位就有一个逗号的数字?它必须匹配以
下数字:
'42'
'1,234'
'6,368,745'
但不会匹配:
'12,34,567' (逗号之间只有两位数字)
'1234' (缺少逗号)
21. 如何写一个正则表达式, 匹配姓 Nakamoto 的完整姓名? 你可以假定名字
总是出现在姓前面, 是一个大写字母开头的单词。该正则表达式必须匹配:
'Satoshi Nakamoto'
'Alice Nakamoto'
'RoboCop Nakamoto'
但不匹配:
'satoshi Nakamoto'(名字没有大写首字母)
'Mr. Nakamoto'(前面的单词包含非字母字符)
'Nakamoto' (没有名字)
'Satoshi nakamoto'(姓没有首字母大写)
22. 如何编写一个正则表达式匹配一个句子,它的第一个词是 Alice、 Bob 或
Carol, 第二个词是 eats、 pets 或 throws, 第三个词是 apples、 cats 或 baseballs。该句
子以句点结束。 这个正则表达式应该不区分大小写。它必须匹配:
'Alice eats apples.'
'Bob pets cats.'
'Carol throws baseballs.'
'Alice throws Apples.'
'BOB EATS CATS.'
但不匹配:
'RoboCop eats apples.'
'ALICE THROWS FOOTBALLS.'
'Carol eats 7 cats.'
1. re.compile() 函数返回 Regex 对象。
2.使用原始字符串是为了让反斜杠不必转义。
3. search() 方法返回 Match 对象。
4. group() 方法返回匹配文本的字符串。
5.分组 0 是整个匹配,分组 1 包含第一组括号,分组 2 包含第二组括号。
6.句号和括号可以用反斜杠转义: \.、 \(和\)。
7.如果正则表达式没有分组,就返回字符串的列表。如果正则表达式有分组,就返回字符串的元组的列表。
8. | 字符表示匹配两个组中的“任何一个”。
9. ? 字符可以表示“匹配前面分组 0 次或 1 次”,或用于表示非贪心匹配。
10. +匹配 1 次或多次。 *匹配 0 次或多次。
11. {3}匹配前面分组的精确 3 次实例。 {3, 5} 匹配 3 至 5 次实例。
12.缩写字符分类\d、 \w 和\s 分别匹配一个数字、单词或空白字符。
13.缩写字符分类\D、 \W 和\S 分别匹配一个字符,它不是数字、单词或空白字符。
14.将 re.I 或 re.IGNORECASE 作为第二个参数传入 re.compile(),让匹配不区分大小写。
15.字符.通常匹配任何字符,换行符除外。如果将 re.DOTALL 作为第二个参数传入 re.compile(),那么点也会匹配换行符。
16. .*执行贪心匹配, .*?执行非贪心匹配。
17. [0-9a-z]或[a-z0-9]
18. 'X drummers, X pipers, five rings, X hens'
19. re.VERBOSE 参数允许为传入 re.compile() 的字符串添加空格和注释。
20. re.compile(r'^\d{1,3}(,{3})*$')将创建这个正则表达式,但其他正则表达式字符串可以生成类似的正则表达式。
21. re.compile(r'[A-Z][a-z]*\sNakamoto')
22 . re.compile(r'(Alice|Bob|Carol)\s(eats|pets|throws)\ s(apples|cats|baseballs)\.',re.IGNORECASE)
强口令检测
写一个函数,它使用正则表达式, 确保传入的口令字符串是强口令。 强口令的
定义是: 长度不少于 8 个字符, 同时包含大写和小写字符, 至少有一位数字。你可
能需要用多个正则表达式来测试该字符串, 以保证它的强度。
def checkPassword(password):
passwordReg = re.compile(r'''
(?=^.{8,}$) # 八位数及以上
((?=.*\d+)) # 至少一位数字
(?![.\n]) # 没有换行符
(?=.*[A-Z]) # 大写任意个
(?=.*[a-z]).*$ # 小写任意个
''', re.VERBOSE)