随笔 - 22  文章 - 0 评论 - 0 阅读 - 76
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

1.不用正则表达式来查找文本模式

def isPhoneNumber(text):
    if len(text) != 12:
        return False
    for i in range(0, 3):
        if not text[i].isdecimal(): #检查字符串是否只包含十进制数字
            return False
    if text[3] != '-':
        return False
    for i in range(4, 7):
        if not text[i].isdecimal():
            return False
    if text[7] != '-':
        return False
    for i in range(8, 12):
        if not text[i].isdecimal():
            return False
    return True
print('415-555-422 is a phone number:')
print(isPhoneNumber('415-555-4242'))
print('Moshi moshi is a phone number:')
print(isPhoneNumber('Moshi moshi'))

上面代码中先定义一个isPhoneNumber()函数,先检查被传入的字符串长度是否为12,然后检查前3个字符是否都是数字,接着检查第4个字符是否为'-',然后检查第5-7个字符是否都是数字,接着检查第8个字符是否为'-',最后检查第9-12个字符是否都是数字。如果所有检查都通过,则返回True,否则返回False。比价繁琐

message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
for i in range(len(message)): #遍历字符串
    chunk = message[i:i+12] #切片,每次取12个字符
    print(chunk)
    if isPhoneNumber(chunk):    #检查是否是电话号码
        print('Phone number found: ' + chunk)
print('Done')

字典切片 每次取12个字符--还得多多实践啊

2.用正则表达式查找文本模式

2.1创建正则表达式对象

python中所有的正则表达式都在re模块中,要使用正则表达式,首先需要导入re模块
向re.compile()传入一个字符串值,re.compile()将返回一个Regex对象。将Regex对象赋值给一个变量,就可以使用Regex对象调用search()方法了。

Regex 对象的 search()方法查找传入的字符串,寻找该正则表达式的所有匹配。如果字符串中没有找到该正则表达式模式,search()方法将返回 None。如果找到了该模式,search()方法将返回一个 Match 对象,Match 对象有一个 group()方法,它返回被查找字符串中实际匹配的文本

import re
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
phoneNumRegex = re.compile(r'\d{3}-\d{3}-\d{4}') #创建Regex对象  r表示原始字符串 \d表示数字 {3}表示3个数字 
mo = phoneNumRegex.search(message) # search()方法查找字符串中的模式
print('Phone number found: ' + mo.group())  # group()方法返回被查找字符串中实际匹配的文本 只会返回第一个匹配项 

Phone number found: 415-555-1011
也可以直接调用search方法

import re
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
mo = re.search(r'\d{3}-\d{3}-\d{4}',message) # search()方法查找字符串中的模式
print('Phone number found: ' + mo.group())  # group()方法返回被查找字符串中实际匹配的文本 只会返回第一个匹配项 

思考

这里compile()函数的作用是什么?为什么可以直接调用search(),findall(),match()方法?
compile()函数的作用是将正则表达式编译成一个Regex对象,然后调用Regex对象的search(),findall(),match()方法,可以更方便地使用正则表达式。

  1. 增加了代码可读性
  2. 提高了正则表达式的复用率
  3. 提高匹配效率:预编译正则表达式模式,避免在每次匹配时重新解析模式

2.2正则表达式复习

  1. 用 import re 导入正则表达式模块。
  2. 用 re.compile()函数创建一个 Regex 对象(记得使用原始字符串)。
  3. 向 Regex 对象的 search()方法传入想查找的字符串。它返回一个 Match 对象。
  4. 调用 Match 对象的 group()方法,返回实际匹配文本的字符串。

3.用正则表达式匹配多个模式

3.1利用括号分组

假定要将区号从电话号码中分离,在正则表达式中添加括号创建分组 (\d\d\d)-(\d\d\d-\d\d\d\d),括号内就是分组,group()方法将返回括号内匹配的文本

import re
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') #创建Regex对象  r表示原始字符串 \d表示数字 {3}表示3个数字 
mo = phoneNumRegex.search(message) # search()方法查找字符串中的模式
print('Phone number found: ' + mo.group(1))  # group()方法返回被查找字符串中实际匹配的文本
print('Phone number found: ' + mo.group(2)) 
print('Phone number found: ' + mo.group(0)) 

Phone number found: 415
Phone number found: 555-1011
Phone number found: 415-555-1011
group()方法有一个可选的参数,用于获取指定分组的内容。group(0)总是返回整个匹配的文本。group(1)返回第一个括号内匹配的文本,group(2)返回第二个括号内匹配的文本,以此类推。

3.2用管道匹配多个模式

要查找多种分组,可以使用管道字符(|)来指定多种分组,用管道字符将不同的分组选项分隔开

import re
heroRegex = re.compile(r'Batman|Tina Fey') #如果 Batman 和 Tina Fey 都出现在被查找的字符串中,第一次出现的匹配文本,
将作为 Match 对象返回
mo1 = heroRegex.search('Batman and Tina Fey.') # search()方法查找字符串中的模式
print(mo1.group())
mo2 = heroRegex.search('Tina Fey and Batman.') # search()方法查找字符串中的模式
print(mo2.group())

3.3用问号实现可选匹配

有时候,想匹配的模式是可选的,也就是说,不论这段文本在不在,正则表达式都会认为匹配成功。要实现可选匹配,可以在模式中添加问号(?)。问号表明它前面的分组在匹配时是可选的

import re
batRegex = re.compile(r'Bat(wo)?man') # wo是可选的
mo1 = batRegex.search('The Adventures of Batman') # search()方法查找字符串中的模式
print(mo1.group())
mo2 = batRegex.search('The Adventures of Batwoman') # search()方法查找字符串中的模式
print(mo2.group())

利用前面的例子,可以让正则表达式寻找包含区号或不包含区号的电话号码。

import re
phoneRegex = re.compile(r'(\d\d\d-)?\d\d\d-\d\d\d\d') # ?表示前面的字符是可选的
mo1 = phoneRegex.search('My number is 415-555-4242.') # search()方法查找字符串中的模式
print(mo1.group())
mo2 = phoneRegex.search('My number is 555-4242.') # search()方法查找字符串中的模式
print(mo2.group())

3.4用星号匹配零次或多次

星号(*)匹配零次或多次前面的分组。星号不要求分组出现在匹配的文本中,因此它也是可选的。星号和问号都可以匹配前面的分组出现零次或多次,问号是匹配零次或一次,二者之间的唯一区别是星号匹配任意次数,包括零次。

import re
batRegex = re.compile(r'Bat(wo)*man') # wo是可选的
mo1 = batRegex.search('The Adventures of Batman') # search()方法查找字符串中的模式
print(mo1.group())
mo2 = batRegex.search('The Adventures of Batwoman') # search()方法查找字符串中的模式
print(mo2.group())
mo3 = batRegex.search('The Adventures of Batwowowowoman') # search()方法查找字符串中的模式
print(mo3.group())

3.5用加号匹配一次或多次

加号(+)和星号类似,也是匹配前面的分组出现一次或多次,但加号要求分组的至少出现一次。

import re
batRegex = re.compile(r'Bat(wo)+man') # wo至少出现一次
mo1 = batRegex.search('The Adventures of Batman') # search()方法查找字符串中的模式
print(mo1 == None)
mo2 = batRegex.search('The Adventures of Batwoman') # search()方法查找字符串中的模式
print(mo2.group())# mo2.group()返回匹配的文本

3.6用花括号匹配特定次数

要匹配的文本重复特定次数,可在花括号({})中指定重复次数。在花括号中只指定一个数字,正则表达式将匹配正好出现指定次数的文本。还可以在花括号中指定一个范围,花括号中的逗号之前是最低重复次数,之后是最高重复次数。

import re
haRegex = re.compile(r'(Ha){3}') #匹配3次Ha
mo1 = haRegex.search('HaHaHa') # search()方法查找字符串中的模式
print(mo1.group()) # mo1.group()返回匹配的文本  匹配三次
mo2 = haRegex.search('Ha') # search()方法查找字符串中的模式
print(mo2 == None)  # mo2 == None表示没有匹配的文本 即没有匹配Ha三次
mo3 = haRegex.search('HaHa') # search()方法查找字符串中的模式
print(mo3 == None)
mo4 = haRegex.search('HaHaHaHa') # search()方法查找字符串中的模式
print(mo4 == None) # 匹配四次  包含了三次
mo5 = haRegex.search('HaHaHaHaHa') # search()方法查找字符串中的模式
print(mo5 == None)

指定范围

import re
haRegex = re.compile(r'(Ha){3,5}') #匹配3次Ha
mo1 = haRegex.search('HaHaHa') # search()方法查找字符串中的模式
print(mo1.group()) # mo1.group()返回匹配的文本  匹配三次
mo2 = haRegex.search('Ha') # search()方法查找字符串中的模式
print(mo2 == None)  # mo2 == None表示没有匹配的文本 即没有匹配Ha三次
mo3 = haRegex.search('HaHa') # search()方法查找字符串中的模式
print(mo3 == None)
mo4 = haRegex.search('HaHaHaHa') # search()方法查找字符串中的模式
print(mo4 == None)
mo5 = haRegex.search('HaHaHaHaHa') # search()方法查找字符串中的模式
print(mo5 == None)

4.贪心和非谈心匹配

在字符串'HaHaHaHa'中,正则表达式(Ha){3,5}可以匹配3次、4次、5次或6次'Ha'。这种正则表达式被称为贪心匹配,它总是匹配尽可能多的文本。要让正则表达式采用非贪心方式匹配,可以在量词后面加上问号(?)。

import re
haRegex = re.compile(r'(Ha){3,5}?') #
mo5 = haRegex.search('HaHaHaHaHa') # search()方法查找字符串中的模式
print(mo5.group()) # mo5.group()返回匹配的文本  匹配五次

HaHaHa

import re
haRegex = re.compile(r'(Ha){3,5}') #
mo5 = haRegex.search('HaHaHaHaHa') # search()方法查找字符串中的模式
print(mo5.group()) # mo5.group()返回匹配的文本  匹配五次

HaHaHaHaHa
非贪心匹配和贪心匹配的区别
贪心():尽可能多的匹配 非贪心(花括号加?)表示尽可能匹配最短的字符串

5.findall()方法

secarch()方法只返回字符串中的一个匹配项。要在字符串中找到所有的匹配项,可以使用findall()方法。调用findall()方法时,它返回一个字符串列表,每个字符串都是匹配的文本。findall()方法在字符串中查找所有非重叠的模式匹配项,然后返回一个包含所有匹配项的列表。
findall()方法返回一个字符串列表,每个字符串都是匹配的文本。在正则表达式中,字符串列表与使用for循环遍历匹配对象所得到的结果相同。

phoneNumRegex = re.compile(r'\d{3}-\d{3}-\d{4}')
mo = phoneNumRegex.search('Cell: 415-555-9999 Work: 212-555-0000')
mo.group()

输出:'415-555-9999'

phoneNumRegex = re.compile(r'\d{3}-\d{3}-\d{4}')
mo = phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
mo

输出:['415-555-9999', '212-555-0000']
如果正则表达式中有分组 那么 findall()方法将返回一个元组列表,每个元组表示一个匹配项。

phoneNumRegex = re.compile(r'(\d{3})-(\d{3})-(\d{4})')
mo = phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
print(mo)

输出:[('415', '555', '9999'), ('212', '555', '0000')]
作为 findall()方法的返回结果的总结,请记住下面两点:

  1. 如果调用在一个没有分组的正则表达式上,例如\d\d\d-\d\d\d-\d\d\d\d,方法findall()将返回一个匹配字符串的列表,例如['415-555-9999', '212-555-0000']。
  2. 如果调用在一个有分组的正则表达式上,例如(\d\d\d)-(\d\d\d)-(\d\d\d\d),方法 findall()将返回一个字符串的元组的列表(每个分组对应一个字符串),例如[('415',
    '555', '1122'), ('212', '555', '0000')]。

6.字符分类

\d 表示0-9的任何数字
\D 表示任何非数字字符
\w 表示任何字母、数字或下划线字符(可以认为是匹配“单词”字符)。等价于[A-Za-z0-9_]。
\W 表示任何非单词字符。
\s 表示任何空格字符,包括空格、制表符、换页符等。等价于[\t\n\r\f\v]。
\S 表示任何非空白字符。

xmasRegex = re.compile(r'\d+\s\w+')
mo = xmasRegex.findall('12 drummers, 11 pipers, 10 lords, 9 ladies, 8 maids, 7\
swans, 6 geese, 5 rings, 4 birds, 3 hens, 2 doves, 1 partridge')
print(mo)

输出:['12 drummers', '11 pipers', '10 lords', '9 ladies', '8 maids', '7 swans', '6 geese', '5 rings', '4 birds', '3 hens', '2 doves', '1 partridge']

7.建立自己的字符分类

有时候你想匹配一组字符,但是\d、\w和\s等字符分类太宽泛了。在这种情况下,你可以使用方括号定义自己的字符分类。例如,\d表示数字0~9,但如果你只想匹配数字2、3、4、5、6、7、8、9,你可以使用[23456789]。

import re
vowelRegex = re.compile(r'[aeiouAEIOU]')
mo = vowelRegex.findall('Robocop eats baby food. BABY FOOD.')
print(mo)

输出:['o', 'o', 'o', 'e', 'a', 'o', 'o', 'o', 'A', 'O', 'O', 'O', 'O', 'O']
方括号内的字符分类是区分大小写的。因此,[AEIOU]只匹配大写元音,而[aeiou]只匹配小写元音。如果你想匹配的大小写元音,可以同时列出这两个分类,如[AaEeIiOoUu]。

8.取反字符分类

在方括号内的字符分类前面加上一个脱字符(^),就可以创建“取反”或“否定”字符分类。即,匹配任何不在方括号内的字符。

import re
vowelRegex = re.compile(r'[^aeiouAEIOU]')
mo = vowelRegex.findall('Robocop eats baby food. BABY FOOD.')
print(mo)

也可以使用短横线表示字母或数字的范围。例如,[a-z0-9]匹配所有小写字母和数字,[A-Z0-9]匹配所有大写字母和数字。

9.插入字符和美元字符

插入字符()匹配字符串的开始,美元字符($)匹配字符串的结尾。例如,Hello匹配以Hello开头的字符串,Hello$匹配以Hello结尾的字符串。

import re
beginsWithHello = re.compile(r'^Hello')
mo1 = beginsWithHello.search('Hello world!')
print(mo1.group())
mo2 = beginsWithHello.search('He said hello.')
print(mo2 == None)

输出:
Hello
True

import re
endsWithNumber = re.compile(r'\d$')
mo1 = endsWithNumber.search('Your number is 42') # search()方法查找字符串中的模式
print(mo1.group())
print(endsWithNumber.findall('Your number is 42'))

输出:
2
['2']
注意 r'\d$'用户匹配单个数字结尾的字符串 而不是整个字符串所以会输出2

import re
endsWithNumber = re.compile(r'\d+$')
mo1 = endsWithNumber.search('Your number is 42')
print(mo1.group(0))  # 输出整个匹配项
print(endsWithNumber.findall('Your number is 42'))

输出:
42
['4', '2']

10.通配字符

句点字符(.)匹配除换行符\n之外的任何字符。句点字符不是正则表达式中的特殊字符,所以你不需要对其进行转义。例如,r.b.匹配任何以字母b开头、后面跟着任意字符、然后是字母b的字符串(注意,这个匹配b字符的任意实例,而不仅仅是下一个字符)。

import re
atRegex = re.compile(r'.at')
mo = atRegex.findall('The cat in the hat sat on the flat mat.')
print(mo)

输出:['cat', 'hat', 'sat', 'lat', 'mat']
如果你想匹配包括换行符\n在内的任何字符,你可以向re.compile()方法传入re.DOTALL作为第二个参数。例如:

import re
noNewlineRegex = re.compile('.*', re.DOTALL)
mo = noNewlineRegex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.')
print(mo.group())

.*匹配字符串中的所有字符,re.DOTALL让句点字符(.)匹配所有字符,包括换行符。
输出:
Serve the public trust.
Protect the innocent.
Uphold the law.

11.正则表达式符号复习

? 匹配前面的字符0次或1次

  • 匹配前面的字符0次或多次
  • 匹配前面的字符1次或多次
    {n} 匹配前面的字符n次
    {n,} 匹配前面的字符n次或多次
    {n,m} 匹配前面的字符n到m次
    ^ 匹配字符串的开头 ^spam 意味着字符串必须以spam开头
    $ 匹配字符串的结尾 ^spam 意味着字符串必须以spam结尾
    . 匹配任何字符(除了\n)
    [...] 匹配字符分类中的任意一个字符
    [^...] 匹配不在字符分类中的任意一个字符
    \d \w \s 匹配数字、单词字符、空白字符
    \D \W \S 匹配非数字、非单词字符、非空白字符

12.不区分大小写的匹配

如果你不关心正则表达式匹配的大小写,可以给re.compile()方法传入re.IGNORECASE(或re.I)作为第二个参数,像这样:

import re
robocop = re.compile(r'robocop', re.I)
mo1 = robocop.search('Robocop is part man, part machine, all cop.')
print(mo1.group())
mo2 = robocop.search('ROBOCOP always gets to the chase.')
print(mo2.group())

输出:
Robocop
ROBOCOP
一个能让你靠自学快速学会任何东西的顶级思维:先做个垃圾出来,然后看看别人是怎么做的,最后再模仿着做出来。
矛盾 主要矛盾

13.用sub()方法替换字符串

将字符串中所有以"Agent "开头的名字替换为只显示首字母和四个星号的形式。

agentNamesRegex = re.compile(r'Agent (\w)\w*')
m1 = agentNamesRegex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.')
print(m1)

输出:
Agent A**** told Agent C**** that Agent E**** knew Agent B**** was a double agent.

必须搞明白下面这个例子

re.sub(pattern, repl, string, count=0, flags=0)

import re

# 基本替换示例
text = "Hello, World!"
new_text = re.sub("World", "Python", text)
print(new_text)  # 输出: Hello, Python!

# 使用分组引用进行替换
text = "Agent Alice"
new_text = re.sub(r"Agent (\w+)", r"Agent \1****", text)
print(new_text)  # 输出: Agent A****

# 使用函数进行替换
def replace_with_upper(match):
    return match.group(1).upper()

text = "abc123"
new_text = re.sub(r'[a-zA-Z+]', replace_with_upper, text)
print(new_text)  # 输出: ABC123
'''
在这段代码中,re.sub函数的第二个参数是replace_with_upper函数。re.sub在执行时会遍历字符串text,寻找所有与正则表达式r'[a-zA-Z]'匹配的子串。每当它找到一个匹配项时,就会调用replace_with_upper函数,并将一个代表这次匹配的re.Match对象传递给replace_with_upper函数。

在replace_with_upper函数内部,你可以通过match.group()获取匹配的文本,然后对这个文本进行处理。在这个例子中,我们将匹配的文本转换为大写。
'''
# 限制替换次数
text = "one1 two2 three3 four4"
new_text = re.sub(r"\d", "0", text, count=2)
print(new_text)  # 输出: one0 two0 three3 four4

14.管理复杂的正则表达式

可以这样写,增加代码可读性

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)

如果需要正则表达式不区分大小写并且.可以匹配换行符,可以给re.compile()传入re.IGNORECASE和re.DOTALL作为第二个参数。
用|分隔

someRegexValue = re.compile('foo', re.IGNORECASE | re.DOTALL)

项目电话号码和 E-mail 地址提取程序

假设你有一个无聊的任务,要在一篇长的网页或文章中,找出所有电话号码和
邮件地址。如果手动翻页,可能需要查找很长时间。如果有一个程序,可以在剪贴
板的文本中查找电话号码和 E-mail 地址,那你就只要按一下 Ctrl-A 选择所有文本,
按下 Ctrl-C 将它复制到剪贴板,然后运行你的程序。它会用找到的电话号码和 E-mail
地址,替换掉剪贴板中的文本
当你开始接手一个新项目时,很容易想要直接开始写代码。但更多的时候,最
好是后退一步,考虑更大的图景。我建议先草拟高层次的计划,弄清楚程序需要做
什么。暂时不要思考真正的代码,稍后再来考虑。现在,先关注大框架。
不错 这点对于一个程序员来说 很重要

  1. 使用 pyperclip 模块复制和粘贴字符串。
  2. 创建两个正则表达式,一个匹配电话号码,另一个匹配 E-mail 地址。对两个正则表达式,找到所有的匹配,而不只是第一次匹配。
  3. 将匹配的字符串整理好格式,放在一个字符串中,用于粘贴。
  4. 如果文本中没有找到匹配,显示某种消息。

为电话号码创建一个正则表达式

phoneRegex = re.compile(r'\d{11}')

为 E-mail 地址创建一个正则表达式

emailRegex = re.compile(r'\w+@\w+.\w+')

找到所有匹配的字符串

text = '12345678901@qq.com'
mo = phoneRegex.findall(text)
print(mo)
mo = emailRegex.findall(text)
print(mo)

#! 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)

# Create email regex.
emailRegex = re.compile(r'''(
    [a-zA-Z0-9._%+-]+      # username
    @                      # @ symbol
    [a-zA-Z0-9.-]+         # domain name
    (\.[a-zA-Z]{2,4}){1,2} # dot-something
    )''', re.VERBOSE)

# 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])

# 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.')

1.创建 Regex 对象的函数是什么?
re.compile() 这个函数接受一个正则表达式模式作为参数,并返回一个Regex对象

import re

# 创建一个 Regex 对象
pattern = re.compile(r'\d+')  # 匹配一个或多个数字

# 使用 Regex 对象进行匹配
match = pattern.match('123abc')

if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

2.在创建 Regex 对象时,为什么常用原始字符串?
转义字符:正则表达式中经常使用反斜杠 \ 来表示特殊字符,例如 \d 表示数字,\w 表示字母或数字。在普通的字符串中,反斜杠也是一个转义字符,例如 \n 表示换行,\t 表示制表符。这会导致在正则表达式中使用普通字符串时,需要写成 \d、\w 等来表示真正的正则表达式。而使用原始字符串,反斜杠 \ 不会被当作转义字符,这样就可以直接写 \d、\w。

可读性:使用原始字符串可以使正则表达式更加简洁和易读,不需要写那么多反斜杠。

避免错误:由于正则表达式中反斜杠的频繁使用,如果不使用原始字符串,很容易出现由于转义字符导致的错误
3.search()方法返回什么?
返回对象

import re

pattern = r'\d+'  # 匹配一个或多个数字
text = 'abc123def456'

match = re.search(pattern, text)

if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

4.如果 search()方法没有找到匹配,它将返回什么?
None
5.findall()方法返回什么?
返回一个字符串列表

import re

pattern = r'\d+'  # 匹配一个或多个数字
text = 'abc123def456'

matches = re.findall(pattern, text)

if matches:
    print("匹配成功:", matches)
else:
    print("匹配失败")

6.如果 Regex 对象在创建时没有使用 re.DOTALL 标志,那么句点 . 在正则表达式中有什么含义?

在正则表达式中,句点 . 通常表示匹配除换行符 \n 之外的任何单个字符。这意味着 . 可以匹配字母、数字、空格、标点符号等任何字符,但不会匹配换行符。

例如,正则表达式 a.b 可以匹配字符串 a1b、a*b、a b 等,但不能匹配 a\nb。

如果你想让 . 匹配包括换行符在内的任何字符,可以使用 re.DOTALL 标志。这个标志会使 . 匹配任何字符,包括换行符。

4.通过 Match 对象,如何得到匹配该模式的实际字符串?
group() 方法
5.用 r'(\d\d\d)-(\d\d\d-\d\d\d\d)'创建的正则表达式中,分组 0 表示什么?分组 1 呢?分组 2 呢?

import re
Rre = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
text = '123-456-7890ddddd'
mo = Rre.search(text)
print(mo.group(0))
print(mo.group(1))
print(mo.group(2))
  • 分组 0:表示整个匹配的字符串。例如,对于输入字符串 '123-456-7890',分组 0 将匹配整个字符串 '123-456-7890'。

  • 分组 1:表示第一个捕获组 (\d\d\d) 匹配的子字符串。这个捕获组匹配三个数字。例如,对于输入字符串 '123-456-7890',分组 1 将匹配 '123'。

  • 分组 2:表示第二个捕获组 (\d\d\d-\d\d\d\d) 匹配的子字符串。这个捕获组匹配三个数字,一个连字 符 -,再跟着四个数字。例如,对于输入字符串 '123-456-7890',分组 2 将匹配
    6.括号和句点在正则表达式语法中有特殊的含义。如何指定正则表达式匹配真正的括号和句点字符?
    使用反斜杠 \ 对括号和句点进行转义,例如 . 和 \

import re

# 匹配真正的括号和句点
pattern = r'\(\.\)'  # 匹配一个左括号,一个句点,一个右括号
text = '(.)'

match = re.search(pattern, text)

if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

7.findall()方法返回一个字符串的列表,或字符串元组的列表。是什么决定它提供哪种返回?
findall()方法返回的列表类型取决于正则表达式中是否使用了括号。如果没有使用括号,findall()方法返回一个字符串列表,每个字符串都是匹配整个正则表达式的子字符串。如果使用了括号,findall()方法返回一个字符串元组的列表,每个元组包含正则表达式中每个括号捕获组的匹配结果。
8.在正则表达式中,|字符表示什么意思?
竖线 | 是一个逻辑“或”运算符。它用于匹配两个或多个模式中的任意一个。
9.在正则表达式中,?字符有哪两种含义?
非贪婪匹配和可选匹配。
10.在正则表达式中,+和*字符之间的区别是什么?

  • 表示匹配前面的字符一次或多次,* 表示匹配前面的字符零次或多次。
    11.在正则表达式中,{3}和{3,5}之间的区别是什么?
    {3} 表示匹配前面的字符恰好 3 次,{3,5} 表示匹配前面的字符至少 3 次,最多 5 次。

12.在正则表达式中,\d、\w 和\s 缩写字符类是什么意思?

  • \d:匹配任何数字字符,相当于 [0-9]。
  • \w:匹配任何字母数字字符,相当于 [a-zA-Z0-9_]。
  • \s:匹配任何空白字符,相当于 [ \t\n\r\f\v]。
    13.在正则表达式中,\D、\W 和\S 缩写字符类是什么意思?
  • \D:匹配任何非数字字符,相当于 [^0-9]。
  • \W:匹配任何非字母数字字符,相当于 [^a-zA-Z0-9_]。
  • \S:匹配任何非空白字符,相当于 [^ \t\n\r\f\v]。
    14.如何让正则表达式不区分大小写?
    使用 re.IGNORECASE 标志。例如:
import re

pattern = re.compile(r'hello', re.IGNORECASE)
text = 'Hello, world!'
match = pattern.search(text)

if match:
    print("匹配成功:", match.group())
else:
    print("匹配失败")

15.字符.通常匹配什么?如果 re.DOTALL 作为第二个参数传递给 re.compile(),它会匹配什么?
字符.通常匹配除换行符之外的任何单个字符。如果 re.DOTALL 作为第二个参数传递给 re.compile(),那么.将匹配任何字符,包括换行符。
16..?之间的区别是什么?

  • 表示匹配前面的字符零次或多次,.* 表示匹配前面的字符零次或多次,尽可能多地匹配字符。*? 表示匹配前面的字符零次或多次,但尽可能少地匹配字符,即非贪婪匹配。
    17.匹配所有数字和小写字母的字符分类语法是什么?
    [0-9a-z]
    18.如果 numRegex = re.compile(r'\d+'),那么 numRegex.sub('X', '12 drummers, 11 pipers, five rings, 3 hens')返回什么?
    'X drummers, X pipers, five rings, X hens'
    19.将 re.VERBOSE 作为第二个参数传递给 re.compile(),让你能做什么?
    允许你在正则表达式中添加注释和空格,使正则表达式更易读。
    20.如何写一个正则表达式,匹配每 3 位就有一个逗号的数字?它必须匹配以下数字:
     '42'

16..?之间的区别是什么?
17.匹配所有数字和小写字母的字符分类语法是什么?
18.如果 numRegex = re.compile(r'\d+'),那么 numRegex.sub('X', '12 drummers, 11 pipers, five rings, 3 hens')返回什么?

numRegex = re.compile(r'\d+')
numRegex.sub('X', '12 drummers, 11 pipers, five rings, 3 hens')
'X drummers, X pipers, five rings, X hens'
# 这里需要注意sub()函数参数 用regex对象调用的时候,第一个参数是替换字符串,第二个参数是要进行替换的字符串
# 从模块调用的时候:第一个参数:正则表达式模式,用于匹配需要替换的字符串部分。第二个参数 repl:用于替换匹配到的字符串部分。可以是字符串或者一个函数。第三个参数 string:要进行替换操作的原始字符串。第四个参数 count:可选参数,表示替换的次数,默认为-1,表示替换所有匹配的部分。
numRegex = re.compile(r'\d+')
re.sub(numRegex,'X', '12 drummers, 11 pipers, five rings, 3 hens')

19.将 re.VERBOSE 作为第二个参数传递给 re.compile(),让你能做什么?

import re

# 使用 re.VERBOSE 标志,使正则表达式更易读
pattern = re.compile(r"""
    \b      # 单词边界
    \w+     # 匹配一个或多个字母、数字或下划线
    \s      # 匹配一个空白字符
    \w+     # 匹配一个或多个字母、数字或下划线
    \b      # 单词边界
    """, re.VERBOSE)

text = "hello world this is a testrrrr"

# 使用编译后的正则表达式进行匹配
matches = pattern.findall(text)

print(matches)
# 输出: ['hello world', 'this is', 'a testrrrr']

20.如何写一个正则表达式,匹配每 3 位就有一个逗号的数字?它必须匹配以下数字:
'42''1,234''6,368,745'
但不会匹配:
'12,34,567' (逗号之间只有两位数字)'1234' (缺少逗号)

import re

# 正则表达式
pattern = r'^\d{1,3}(?:,\d{3})*$'  # ^\d{1,3} 匹配1到3位的数字 (?:,\d{3})*$ 匹配0个或多个逗号和3位的数字
# ?:,\d{3} 是一个非捕获组,用于匹配逗号和3位的数字,但不捕获匹配的内容
# 测试字符串
test_strings = [
    "42",
    "1,234",
    "6,368,745",
    "12,34,567",
    "1234"
]

# 查找并打印每个字符串中匹配正则表达式的部分
for s in test_strings:
    for match in re.finditer(pattern, s):# 这里用finditer()函数,它会返回一个迭代器,每次迭代返回一个Match对象,而不是字符串本身。
        print(f"在字符串中找到匹配的部分:'{match.group()}'")
    else:
        print(f"在字符串 '{s}' 中没有找到匹配的部分。")

21.如何写一个正则表达式,匹配姓 Nakamoto 的完整姓名?你可以假定名字总是出现在姓前面,是一个大写字母开头的单词。该正则表达式必须匹配:
 'Satoshi Nakamoto'
 'Alice Nakamoto'
 'RoboCop Nakamoto'
但不匹配:
 'satoshi Nakamoto'(名字没有大写首字母)
 'Mr. Nakamoto'(前面的单词包含非字母字符)
 'Nakamoto' (没有名字)
 'Satoshi nakamoto'(姓没有首字母大写)
r'[A-Z]{1}\w+ Nakamoto'

pattern = rr'[A-Z]{1}\w+\s*Nakamoto'# \s* 表示匹配零个或多个空格
text = ['Satoshi Nakamoto', 'Alice Nakamoto', 'RoboCop Nakamoto', 'Mr. Nakamoto']
for name in text:
    match = re.findall(pattern, name)
    if match:
        print(match)
    else:
        print('No match')
# 输出:
# ['Satoshi']
# ['Alice']
# ['RoboCop']
# No match

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.'

r'Alice|Bob|Carol\s(eats|pets|throws)\s(apples|cats|baseballs).'

import re

# 正则表达式
pattern = r'^(Alice|Bob|Carol)\s+(eats|pets|throws)\s+(apples|cats|baseballs)\.$'

# 测试字符串
test_strings = [
    "Alice eats apples.",
    "Bob pets cats.",
    "Carol throws baseballs.",
    "Alice pets dogs.",
    "Bob eats apples, cats, and baseballs."
]

# 查找并打印每个字符串中匹配正则表达式的部分
for s in test_strings:
    if re.match(pattern, s):
        print(f"匹配的句子:'{s}'")
    else:
        print(f"不匹配的句子:'{s}'")

在正则表达式中,括号 () 具有分组和捕获的双重功能。具体是分组还是捕获,取决于你是否关心括号内匹配的文本。以下是一些使用括号的场景:

分组(Grouping)

当你想要将表达式的一部分组合在一起,以便应用量词或者创建更复杂的模式时,你使用括号进行分组。在这种情况下,括号不捕获匹配的文本。

例子:

  • a(b|c)d 匹配 "abd" 或 "acd"。括号内的 b|c 被分组在一起,表示 "b" 或 "c" 中的一个。
  • (ab)+ 匹配一个或多个 "ab"。括号将 "ab" 分组在一起,使得 + 可以应用于整个 "ab"。

捕获(Capturing)

当你想要获取括号内匹配的文本时,括号执行捕获功能。捕获的文本被存储在匹配对象的组中,可以通过组号或组名来引用。

例子:

  • re.search(r'(ab)+', 'ababab').group(1) 匹配 "ababab" 中的 "ab"。group(1) 返回第一个捕获组匹配的内容 "ab"。
  • re.search(r'(?P<word>\w+)', 'Hello World').group('word') 匹配 "Hello World" 中的 "Hello"。(?P<word>\w+) 创建了一个命名的捕获组 "word",group('word') 返回该捕获组匹配的内容 "Hello"。

非捕获组(Non-capturing groups)

如果你只需要分组,而不需要捕获匹配的文本,可以使用非捕获组。非捕获组由 ?: 标志表示,放在括号内部。

例子:

  • (?:ab)+ 匹配一个或多个 "ab",但不会捕获 "ab"。
  • re.search(r'(?:ab)+', 'ababab').groups() 返回一个空元组,因为没有任何捕获组。

总结

  • 分组:使用括号 () 来创建一个分组,以便应用量词或构建更复杂的模式。
  • 捕获:使用括号 () 来捕获匹配的文本,可以通过组号或组名来引用。
  • 非捕获组:使用 ?: 标志在括号内部 (?...) 来创建一个非捕获组,这样分组内的文本不会被捕获。

括号何时分组,何时捕获,完全取决于你的需求。如果你不需要括号内匹配的文本,可以使用非捕获组来提高正则表达式的效率,因为非捕获组不会存储匹配的文本。

实践项目

写一个函数,它使用正则表达式,确保传入的口令字符串是强口令。强口令的定义是:长度不少于 8 个字符,同时包含大写和小写字符,至少有一位数字。你可能需要用多个正则表达式来测试该字符串,以保证它的强度。

import re  # 导入正则表达式模块
def strong_password(password):
    # 检查密码长度是否小于8,如果是则返回False,表示密码强度不足
    if len(password) < 8:
        return False
    # 使用正则表达式查找密码中是否包含大写字母,如果没有则返回False
    if not re.findall(r'[A-Z]',password):
        return False
    # 使用正则表达式查找密码中是否包含小写字母,如果没有则返回False
    if not re.findall(r'[a-z]',password):
        return False
    # 使用正则表达式查找密码中是否包含数字,如果没有则返回False
    if not re.findall(r'\d',password):
        return False
    # 如果以上条件都满足,则返回True,表示密码强度足够
    else:
        return True
print(strong_password('Aa123456S'))

习题

23.编写一个函数,它使用正则表达式,从字符串中移除所有 HTML 标签,并返回清理后的字符串。

import re

def remove_html_tags(text):
    # 使用正则表达式匹配并替换所有的 HTML 标签
    cleaned_text = re.sub(r'<[^>]+>', '', text)
    return cleaned_text

# 测试函数
html_text = '<p>This is a <a href="http://example.com">link</a>.</p>'
cleaned_text = remove_html_tags(html_text)

strip()的正则表达式版本
写一个函数,它接受一个字符串,做的事情和 strip()字符串方法一样。如果只
传入了要去除的字符串,没有其他参数,那么就从该字符串首尾去除空白字符。否
则,函数第二个参数指定的字符将从该字符串中去除。

import re
def strip(text, chars=None):
    # 如果没有传入 chars 参数,则默认去除
    if chars is None:
        #使用正则表达式匹配并替换收尾字符
        cleaned_text = re.sub(r'^\s+|\s+$', '', text)
    else:
        # 使用正则表达式匹配并替换指定的字符
        cleaned_text = re.sub(r'^[' + chars + ']+|[' + chars + ']+$', '', text)
    return cleaned_text

# 测试函数
text1 = '   Hello, World!   '
text2 = '***Hello, World!***'
text3 = '---Hello, World!---'
text4 = '+++Hello, World!+++'
print(strip(text1))  # 输出: 'Hello, World!'
print(strip(text2,'*'))  # 输出: 'Hello, World!'

还是得多练习啊 有些知识不熟练根本就不会用

posted on   Martinl_it  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示