python 正则学习笔记

正则表达式

1.单个字符的匹配

re.findall(正则表达式,字符串) :把符合正则表达式的字符串存在列表中返回

1.1 预定义字符集

预定义字符集 作用
\d 匹配数字
\D 匹配非数字
\w 匹配字母数字下划线
\W 匹配非字母或数字或下划线
\s 匹配任意的空白符 (\n \t \r ' ')
\S 匹配任意非空白符
\n 匹配一个换行符
\t 匹配一个制表符
| a|b 匹配字符a 或者 匹配字符b
1.1.1 \d 匹配数字
import re
strvar = "sdfsdf*(&*(&(2ui3"
lst = re.findall("\d",strvar)
print(lst)
1.1.2 \D 匹配非数字
strvar = "sdfsdf*(&*(&(2ui3"
lst = re.findall("\D",strvar)
print(lst)
1.1.3 \w 匹配字母数字下划线
strvar = "sadf*)(*_)456你你好"
lst = re.findall("\w",strvar)
print(lst)
1.1.4 \W 匹配非字母或数字或下划线
strvar = "sadf*)(*_)456你你好"
lst = re.findall("\W",strvar)
print(lst)
1.1.5 \s 匹配任意的空白符 (\n \t \r ' ')
strvar = "     				 "
lst = re.findall("\s",strvar)
print(lst)
1.1.6 \S 匹配任意非空白符
strvar = "    abdd 						"
lst = re.findall("\S",strvar)
print(lst)
1.1.7 \n 匹配一个换行符
strvar = """

"""
lst = re.findall(r"\n",strvar)
print(lst)
1.1.8 \t 匹配一个制表符
strvar = """
				
"""
lst = re.findall(r"\t",strvar)
print(lst)
1.1.9 | 代表或
strvar = "abcdefg"
lst = re.findall("a|b",strvar)
print(lst)

# 在使用|的时候,把不容易匹配到的字符串放到前面,把容易匹配到的放到后面
strvar = "abciuiuabcdwerewr"
lst = re.findall("abc|abcd",strvar)
lst = re.findall("abcd|abc",strvar)
print(lst)

1.2 字符组 [ ]

必须从字符组列举出来的字符当中抽取,默认一个,如果没有返回空

strvar = "abpoiuc"
lst = re.findall("[abc]",strvar)
print(lst) # ['a', 'b', 'c']

print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb
print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb')) # a1b a2b a3b
1.2.1 字符组中的 -

- 代表到,代表的是范围。

print(re.findall('a[0-9]b','a1b a2b a3b acb ayb'))  # a1b a2b a3b
print(re.findall('a[a-z]b','a1b a2b a3b acb ayb adb')) # acb ayb adb
# A-G => ABCDEFG

0-z 不会单纯的匹配小写大写字母和数字,还会匹配到特殊的符号,比如_和@

匹配小写大写字母和数字:[0-9a-zA-Z]

# 0-z 不会单纯的匹配小写大写字母和数字,还会匹配到特殊的符号,比如_和@
print(re.findall('a[0-z]b','a_ba@b aab aAb aWb aqba1b')) #a_b a@b aab aAb aWb aqb a1b
# [0-9a-zA-Z] 匹配小写大写字母和数字
print(re.findall('a[0-9a-zA-Z]b','a1/b a2b a29b a56b a456b')) # a2b
1.2.2 字符组中的^

^ :除了 , 在字符组当中,开头的位置使用

print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) #a%b a&b
1.2.3 匹配^ -\

如果想要匹配^ - 需要前面加上\进行转义

lst = re.findall("a[\^\-]b","a+b a-b a^b")
print(lst) # ['a-b', 'a^b'] 

lst = re.findall(r"a\\b",r"a\b")  # \b 本身也是转义字符 : 退格(把光标向左移动一位)
print(lst[0]) 

2.多个字符的匹配

2.1 量词

  • ? 匹配0个或者1个a

  • + 匹配1个或者多个a

  • * 匹配0个或者多个a

  • {m,n} 匹配m个至n个a

    # 1) ? 匹配0个或者1个a
    print(re.findall('a?b','abbzab abb aab'))  # ab b ab ab b ab
    
    # 2) + 匹配1个或者多个a
    print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab
    
    # 3) * 匹配0个或者多个a 
    print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
    
    # 4) {m,n} 匹配m个至n个a
    # 1 <= x <= 3
    print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab
    # {2,} 至少2次
    print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab
    # {2} 必须2次
    print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
    

2.2 贪婪匹配和非贪婪匹配

贪婪匹配 : 默认向更多次数匹配(回溯算法)

回溯算法 : 从左向右进行匹配,直到匹配到最后,再也找不到了,回头,找最后一个(递归)

.除了\n,匹配所有字符

\. 代表的.这个字符本身,不转义

strvar = "刘能和刘老根和刘铁柱子111子222"
lst = re.findall("刘.",strvar) # [刘能,刘老,刘铁]
print(lst)

lst = re.findall("刘.?",strvar) # ['刘能', '刘老', '刘铁']
print(lst)

lst = re.findall("刘.+",strvar) # ['刘能和刘老根和刘铁柱子111子222']
print(lst)

lst = re.findall("刘.*",strvar) # ['刘能和刘老根和刘铁柱子111子222']
print(lst)

lst = re.findall("刘.{4,}子",strvar) # ['刘能和刘老根和刘铁柱子111子']
print(lst)

非贪婪匹配 : 默认向更少次数匹配(在量词的后面接? .?? .+? .*? {4,}?)

lst = re.findall("刘.??",strvar) # ['刘', '刘', '刘']
print(lst)

lst = re.findall("刘.+?",strvar) # 刘能 刘老 刘铁
print(lst)

lst = re.findall("刘.*?",strvar) # ['刘', '刘', '刘']
print(lst)

lst = re.findall("刘.{4,}?子",strvar) # ['刘能和刘老根和刘铁柱子']
print(lst)

2.3 边界符 \b

\b 本身也是转义字符 : 退格(把光标向左移动一位)

只要不是字母数字下划线都可以形成边界

右边界: d\b

strvar = "word pwd scf"
lst = re.findall(r"d\b",strvar)
print(lst) # [d,d]

lst = re.findall(r".*d\b",strvar)
print(lst) #  ['word pwd']

lst = re.findall(r".*?d\b",strvar)
print(lst) # ['word', ' pwd']

左边界: \bw

lst = re.findall(r"\bw",strvar)
print(lst)

# 要所有w开头的单词
lst = re.findall(r"\bw.*",strvar)
print(lst) # ['word pwd scf']

lst = re.findall(r"\bw.*?",strvar)
print(lst) # ['w']

lst = re.findall(r"\bw.* ",strvar)
print(lst) # ['word pwd ']

lst = re.findall(r"\bw.*? ",strvar)
print(lst) # ['word ']

lst = re.findall(r"w\S*",strvar)
print(lst)

2.4 ^$

^ 匹配字符串的开始(必须以... 开头)

$ 匹配字符串的结尾(必须以... 结尾)

当使用^ 和 $ 符号的时候,要把字符串看成整体

strvar = "大哥大嫂大爷" 
print(re.findall('大.',strvar))  # ['大哥', '大嫂', '大爷']
print(re.findall('^大.',strvar)) # ['大哥']
print(re.findall('大.$',strvar)) # ['大爷']
print(re.findall('^大.$',strvar)) # []
print(re.findall('^大.*?$',strvar)) # ['大哥大嫂大爷']
print(re.findall('^大.*?大$',strvar)) # []
print(re.findall('^大.*?爷$',strvar)) # ['大哥大嫂大爷']

3.匹配分组()

3.1 () 的用法

() 优先显示括号里面的内容

import re
print(re.findall('(.*?)_good','wusir_good alex_good secret男_good')) # ['wusir', ' alex', ' secret男']

?: 取消显示括号里面的内容

print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good')) # ['wusir_good', ' alex_good', ' secret男_good']

匹配小数和整数

strvar = ".34 .... 78.   78.12 56.3 .3 .4 .5 "

# 不用分组写法
lst = re.findall(r"\d+\.\d+|\d+",strvar)
print(lst)
# 分组来表达小数和整数
lst = re.findall(r"\d+(\.\d+)?",strvar)
print(lst)

lst = re.findall(r"\d+(?:\.\d+)?",strvar)
print(lst) # ['34', '78', '78.12', '56.3', '3', '4', '5']

匹配135或171的手机号

strvar = "13566668888 17166668888"
lst = re.findall(r"(?:135|171)\d{8}",strvar)
print(lst)

用^$卡死长度,只能是一个手机号,不能是多个

strvar = "13566668888"
lst = re.findall(r"^(?:135|171)\d{8}$",strvar)
print(lst)

匹配www.baidu.com 或者 www.123.com

strvar = "www.baidu.com www.lagou.com www.123.com"
lst = re.findall(r"(?:www).(?:baidu|123).(?:com)",strvar)
print(lst)

findall 是把所有符合条件的内容都匹配出来放到列表里

search 按照正则表达式,把第一次匹配到的内容返回出来,返回的是对象。如果匹配不到内容,返回的是None ,无法调用group 或者groups方法的。

strvar = "www.baidu.com www.lagou.com www.123.com"
obj = re.search(r"www\.(baidu|123)\.(com)",strvar)

# 返回的是匹配到的结果
res = obj.group()
print(res)

# 通过group和下标可以获取到括号的内容(了解)
print(obj.group(1))
print(obj.group(2))

# 返回的是括号分组里面的内容
res = obj.groups()
print(res)

4.命名分组

4.1 反向引用

在匹配到的值,在引用一次

# \1 把第一个小括号里面的内容,拿出来在匹配一下
lst = re.findall(r"<(.*?)>(.*?)<(/\1)>",strvar)
print(lst)

# \1 代表反向引用第一个括号内容  \2代表反向引用第二个括号内容
strvar = "a1b2cab"
obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar)
print(obj)
# 获取匹配到的内容
res1 = obj.group()
print(res1)
# 获取分组里面的内容
res2 = obj.groups()
print(res2)

4.2 命名分组

(?P<组名>正则表达式) 给这个组起一个名字

(?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置

# 方法一
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)\1\2",strvar)
# 获取匹配到的内容
res1 = obj.group()
print(res1)
# 获取分组里面的内容
res2 = obj.groups()
print(res2)

# 方法二
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar)
# 获取匹配到的内容
res1 = obj.group()
print(res1)
# 获取分组里面的内容
res2 = obj.groups()
print(res2)

正则函数

通过正则匹配出第一个对象返回,通过group取出对象中的值

strvar = "1+2 3*4"
obj = re.search("\d+(.*?)\d+",strvar)
print(obj)
# 返回匹配到的内容(匹配到一个就返回)
res = obj.group()
print(res)
# 返回分组里面的内容,类型是元组
tup = obj.groups()
print(tup[0])

2. match

当search函数里面的正则表达式前面加上^ 等价于 math的用法

strvar = "a13566668888"
# strvar = "13566668888"
obj = re.search("^\d+",strvar)
print(obj)  # None
# print(obj.group())

obj = re.match("\d+",strvar)
print(obj)
# print(obj.group())

3. split

# split    切割
strvar = "alex|xboyww&wusir%ritian"
res = re.split("[|&%]",strvar)
print(res)  # ['alex', 'xboyww', 'wusir', 'ritian']

strvar = "alex234234xboyww6786wusir78967896ritian"
# [0-9] <=> \d
res = re.split("\d+",strvar)
# res = re.split("[0-9]+",strvar)
print(res)  # ['alex', 'xboyww', 'wusir', 'ritian']

4. sub

sub(正则,要替换的字符,原字符串[,次数])

strvar = "alex|xboyww&wusir%ritian"
res = re.sub("[|&%]","-",strvar)
print(res) # alex-xboyww-wusir-ritian
strvar = "alex|xboyww&wusir%ritian"
res = re.sub("[|&%]","-",strvar,2)
print(res) # alex-xboyww-wusir%ritian

5. subn

用法和sub一样,区别在于返回的是元组 (结果,次数)

strvar = "alex|xboyww&wusir%ritian"
res = re.subn("[|&%]","-",strvar)
res = re.subn("[|&%]","-",strvar,1)
print(res) # ('alex-xboyww&wusir%ritian', 1)

6. finditer

匹配字符串中相应内容,返回迭代器[迭代器中包含的是对象]

from collections import Iterator , Iterable
strvar = "jkasdfjkadfjk1234asfj2342kfa"
it = re.finditer("\d+",strvar)
print(isinstance(it,Iterator))

# 获取迭代器里面的内容
for i in it:
	print(i.group())

7. compile

正常情况下,正则表达式编译一次,执行一次.如果想要编译一次,多次使用的话,使用compile

compile 可以编译一次,终身受益.节省系统的资源

strvar = "jksdjdfsj72343789asdfaj234"
pattern = re.compile("\d+")
print(pattern)
lst = pattern.findall(strvar)
print(lst)
obj = pattern.search(strvar)
print(obj.group())

8. 正则表达式修饰符

修饰符 作用
re.I 使匹配对大小写不敏感
re.M 使每一行都能够单独匹配(多行),影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符

8.1 re.I 使匹配对大小写不敏感

strvar = "<h1>asdASD</H1>"
pattern = re.compile(r"<h1>(.*?)</h1>",flags=re.I)
obj = pattern.search(strvar)
print(obj) # <_sre.SRE_Match object; span=(0, 15), match='<h1>asdASD</H1>'>
print(obj.group()) # <h1>asdASD</H1>

8.2 re.M 使每一行都能够单独匹配(多行),影响 ^ 和 $

strvar = """<h1>72347923489</H1>
<p>72347923489</p>
<li>72347923489</li>
"""
pattern = re.compile("^<.*?>(?:.*?)<.*?>$",flags=re.M)
lst = pattern.findall(strvar)
print(lst) #['<h1>72347923489</H1>', '<p>72347923489</p>', '<li>72347923489</li>']

8.3 re.S 使 . 匹配包括换行在内的所有字符

strar = """give
1234234234mefive
"""

pattern = re.compile("(.*?)mefive",flags=re.S)
obj = pattern.search(strar)
print(obj)
print(obj.group())

8.4 可以加多个修饰符 通过| 拼接

pattern = re.compile("(.*?)mefive",flags=re.S|re.I|re.M)
posted @ 2021-09-19 12:31  wangfan000  阅读(65)  评论(0编辑  收藏  举报