超详细:正则表达式从入门到入门
本文章首发于公众号Python for Finance链接:https://mp.weixin.qq.com/s/boLdKv1L31377dLOKQ6irw正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
文章目录
本文章首发于公众号Python for Finance
链接:https://mp.weixin.qq.com/s/boLdKv1L31377dLOKQ6irw
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
匹配字符
代码 | 功能 |
---|---|
. | 通配符,匹配任意1个字符(除了\n换行) |
[ ] | 匹配[ ]中列举的字符,里面的元素之间存在“或”的关系,[abc] 只能匹配a或b或c |
\d | 匹配数字,等价于[0,9] |
\D | 匹配非数字,等价于[^0-9] |
\s | 匹配空白,常见的空白符的形式有空格、制表符 (\t)、换行 (\n) 和回车 (\r) |
\S | 匹配非空白 |
\w | 匹配非特殊字符,即a-z、A-Z、0-9、_、中文 |
\W | 匹配特殊字符 |
\d \D
匹配数字
import re
str0 = """北向资金尾盘回流,全天净买入18.54亿元,连续4日加仓"""
result = re.findall(r'\d', str0) # 加上r模式是为了防止Python中的转义字符与正则表达式中的元字符
print(result)
结果为:
['1', '8', '5', '4', '4']
匹配非数字
import re
str0 = """北向资金尾盘回流,全天净买入18.54亿元,连续4日加仓"""
result = re.findall(r'\D', str0) # 加上r模式是为了防止Python中的转义字符与正则表达式中的元字符
print(result)
结果为:
['北', '向', '资', '金', '尾', '盘', '回', '流', ',', '全', '天', '净', '买', '入', '.', '亿', '元', ',', '连', '续', '日', '加', '仓']
\s \S
text = '''please don't
leave me
alone'''
result = re.findall(r'\s',text)
print(result)
结果为:
[' ', ' ', '\n', ' ', ' ', '\n']
量词:匹配多个字符
某个字符后的数量限定符(*
、 ?
、 +
)用来限定前面这个字符允许出现的个数。最常见的数量限定符包括 *
、 ?
和 +
(不加数量限定则代表出现一次且仅出现一次)
符号 | 匹配规则 | 示例 |
---|---|---|
* | 匹配前一个字符出现0到多次,即可有可无,等价于{0,} | ab*c 匹配 ac , abc , abbc , abbbc |
+ | 匹配前一个字符出现1到多次,即至少有1次,等价于{1,} | colou?r 匹配 color 和 colour |
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有,等价于{0,1} | ab+c 匹配 abc , abbc , abbbc 等等,但不匹配 ac |
{n} | 匹配前一个字符出现n次 | |
{n,} | 匹配前一个字符至少出现n次 | |
{n,m} | 匹配前一个字符出现从n到m次 |
import re
str0 = """北向资金尾盘回流,全天净买入18.54亿元,连续4日加仓;其中沪股通净买入26.41亿元,深股通净卖出7.87亿元。"""
result = re.findall(r'\d+', str0)
print(result)
“+”在正则表达式里代表的是“匹配前面的子表达式一次或多次”。
在“\d+”中,子表达式就是“\d”,一个“\d”是匹配一个数字,“\d+”则就是匹配一个或者多个数字。
结果为:
['18', '54', '4', '26', '41', '7', '87']
在以上结果中,数字被小数点分开了,如18.54被分成了18和54。那么我们可以再做这样的改进。
result = re.findall(r'[\d.]+', str0)
print(result)
[]方括号代表字符集合。匹配所包含的任意一个字符。“[\d.]”即匹配一个“\d”或者一个“.”字符,再带上加“+”,就可以匹配一个或者多个了。
结果为:
['18.54', '4', '26.41', '7.87']
星号*
*+:字符u可以出现0次或1次或者多次
a = re.findall(r'colou*r', 'color')
print(a)
b = re.findall(r'colou*r', 'colour')
print(b)
c = re.findall(r'colou*r', 'colouuur')
print(c)
结果为:
['color']
['colour']
['colouuur']
加号+
u+:字符u可以出现 1 次或多次
a = re.findall(r'colou+r', 'color')
print(a)
b = re.findall(r'colou+r', 'colour')
print(b)
c = re.findall(r'colou+r', 'colouuur')
print(c)
结果为:
[]
['colour']
['colouuur']
问号?
u?:字符u可以出现 0 次或 1 次
a = re.findall(r'colou?r', 'color')
print(a)
b = re.findall(r'colou?r', 'colour')
print(b)
c = re.findall(r'colou?r', 'colouuur')
print(c)
结果为:
['color']
['colour']
[]
大括号{}
有的时候我们非常明确要匹配的字符出现几次,比如
- 中国的手机号位数是 13 位,n = 13
- 密码需要 8 位以上,n ≥ 8
- 用户名需要在 8 到 16 位之间,8 ≤ n ≤ 16
这时我们可以设定具体的上界或(和)下界,使得代码更加有效也更好读懂,规则如下:
- {n} 左边的字符串是否出现 n 次
- {n, } 左边的字符串是否出现大于等于 n 次
- {, n} 左边的字符串是否出现小于等于 n 次
- {n, m} 左边的字符串是否出现在 n 次和 m 次之间
import re
a = re.findall(r'[a-z]{1}','a11bbb2222ccccc')
print(a)
b = re.findall(r'[0-9]{2,}','a11bbb2222ccccc')
print(b)
c = re.findall(r'[a-z]{1,4}','a11bbb2222ccccc')
print(c)
d = re.findall(r'[0-9]{2,3}','a11bbb2222ccccc')
print(d)
结果为:
['a', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'c']
['11', '2222']
['a', 'bbb', 'cccc', 'c']
['11', '222']
集合字符[]
中括号表示一个字符集,即创建的模式匹配中括号里指定字符集中的任意一个字符,字符集有三种方式来表现:
- 明确字符:
[abc]
会匹配字符 a,b 或者 c - 范围字符:
[a-z]
会匹配字符 a 到 z - 补集字符:
[^6]
会匹配除了 6 以外的字符
明确字符
import re
result = re.findall(r'[abc]','abandon')
print(result)
结果为:
['a', 'b', 'a']
范围字符
在 [ ] 中加入 - 即可设定范围,比如:
- [a-e] = [abcde]
- [1-4] = [1234]
- [a-ep] = [abcdep]
- [0-38] = [01238]
- [A-Za-z0-9_] = 大小写字母、数字、下划线
补集字符
在 [ ] 中加入 ^ 即可除去后面的字符集,比如
- [^abc] 就是非 a, b, c 的字符
- [^123] 就是非 1, 2, 3 的字符
import re
result = re.findall(r'[^abc]','baba')
print(result)
result = re.findall(r'[^abc]','steven')
print(result)
result = re.findall(r'[^123]','456')
print(result)
result = re.findall(r'[^123]','1+2=3')
print(result)
结果为:
[]
['s', 't', 'e', 'v', 'e', 'n']
['4', '5', '6']
['+', '=']
常见字符集
常见的字符集有:
[A-Za-z0-9]
表示匹配任意大小写字母和单个数字[a-z]
表示匹配a至z之间的一个小写英文字母[A-Z]
表示匹配A至Z之间的一个大写英文字母[0-9]
表示匹配0至9之间的一个数字[\u4e00-\u9fa5]
表示匹配中文字符
当然,也可以进行组合,比如说:
[a-zA-Z0-9_\u4e00-\u9fa5]+
表示匹配至少一个汉字、数字、字母、下划线
import re
str0 = """北向资金尾盘回流,全天净买入18.54亿元,连续4日加仓;其中沪股通净买入26.41亿元,深股通净卖出7.87亿元。"""
result = re.findall(r"[\u4e00-\u9fa5]+", str0) # 匹配中文字符
print(result)
结果为:
['北向资金尾盘回流', '全天净买入', '亿元', '连续', '日加仓', '其中沪股通净买入', '亿元', '深股通净卖出', '亿元']
贪婪模式和非贪婪模式
匹配开头和结尾
符号 | 匹配规则 |
---|---|
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
import re
a = re.findall(r'^s','son')
print(a)
b = re.findall(r'^s','abs')
print(b)
c = re.findall(r's$','son')
print(c)
d = re.findall(r's$','abs')
print(d)
结果为:
['s']
[]
[]
['s']
贪婪模式和非贪婪模式
在Python的正则表达式中,默认是贪婪模式,尽可能多的匹配;在量词后面直接加上一个问号"?",可以将贪婪模式转换成为非贪婪模式,尽可能少的匹配,即一旦匹配到结果就结束。
量词包括如下:
-
{m,n}
-
*:{0,}。
-
+:{1,}。
-
?:{0,1}。
【例1】
import re
# '.*' 表示匹配 0 个或多个任意字符
a = re.search('11.*11', '11-22-11-22-11')
print('贪婪模式:',a.group())
# 加上 '?' 设置为非贪婪模式
b = re.search('11.*?11', '11-22-11-22-11')
print('非贪婪模式:',b.group())
结果为:
贪婪模式: 11-22-11-22-11
非贪婪模式: 11-22-11
【例2】
# '.*' 表示匹配 0 个或多个任意字符
a = re.search(r'a.*c', 'sljad38c32ic')
print('贪婪模式:',a.group())
# 变为非贪婪模式,尽可能少的匹配
b = re.search(r'a.*?c', 'sljad38c32ic')
print('非贪婪模式:',b.group())
结果为:
贪婪模式: ad38c32ic
非贪婪模式: ad38c
【例3】
# 想要取b2个到5个,非贪婪模式尽可能少取,取2个,贪婪模式全取
a = re.search(r'ab{2,5}', 'abbbbbb')
print('贪婪模式:', a.group())
b = re.search(r'ab{2,5}?', 'abbbbbb')
print('非贪婪模式:', b.group())
结果为:
贪婪模式: abbbbb
非贪婪模式: abb
【例4】
# 在满足条件的基础上尽可能少取,下面全取才能满足匹配条件
a = re.search(r'ab(\d+)sd', 'ab2345sdd')
print('贪婪模式:',a.group())
b = re.search(r'ab(\d+?)sd', 'ab2345sdd')
print('非贪婪模式:',b.group())
结果为:
贪婪模式: ab2345sd
非贪婪模式: ab2345sd
【例5】
reg_string = "pythonnnnnnnnnpythonHellopytho"
a = re.findall("python*",reg_string)
print(a)
b = re.findall("python+",reg_string)
print(b)
c = re.findall("python*?",reg_string)
print(c)
d = re.findall("python+?",reg_string)
print(d)
结果为:
['pythonnnnnnnnn', 'python', 'pytho']
['pythonnnnnnnnn', 'python']
['pytho', 'pytho', 'pytho']
['python', 'python']
【例8】
heading = r'<>TITLE</h1>'
a = re.findall("<.+>",heading)
print(a)
b = re.findall("<.+?>",heading)
print(b)
c = re.findall("<.8>",heading)
print(c)
d = re.findall("<.*?>",heading)
print(d)
结果为:
['<>TITLE</h1>']
['<>TITLE</h1>']
['<>TITLE</h1>']
['<>', '</h1>']
常用函数
re.findall()
re.findall()
方法用于在字符串中查找正则表达式匹配的所有子串,并返回一个列表。如果没有匹配项,返回一个空列表。
re.findall(pattern, string, flags=0)
- pattern:匹配的正则表达式,必选参数。
- string:要匹配的字符串,必选参数。
- flags:标志位。
import re
result = re.findall(r"\d", "2 apples, 5 bananas, 1 orange")
print(result) # ['2', '5', '1']
re.search()
re.search
扫描整个字符串并返回第一个成功的匹配。
re.match(pattern, string, flags = 0)
- pattern:匹配的正则表达式,必选参数。
- string:要匹配的字符串,必选参数。
- flags:标志位。
import re
result = re.search(r"\d", "2 apples, 5 bananas, 1 orange")
print(result)
结果为:
<re.Match object; span=(0, 1), match='2'>
re.search
将返回一个 MatchObject,属性如下表所示。
方法/属性 | 作用 |
---|---|
group() | 返回被re 匹配的字符串 |
start() | 返回匹配开始的位置 |
end() | 返回匹配结束的位置 |
span() | 返回一个元组包含匹配 (开始,结束) 的位置 |
import re
result = re.search(r"\d", "2 apples, 5 bananas, 1 orange")
print(result.group())
print(result.start())
print(result.end())
print(result.span())
结果为:
2
0
1
(0, 1)
re.compile()
re.compile()
方法用于将正则表达式编译为一个模式对象,该模式对象可以用于匹配字符串。
import re
regex = re.compile(r"\d+")
result = regex.findall("2 apples, 5 bananas, 1 orange")
print(result) # ['2', '5', '1']
re.split()
re.split()
方法用于在字符串中使用正则表达式进行分割,并返回一个列表。
re.split(pattern, string, maxsplit=0, flags=0)
- pattern:匹配的正则表达式,必选参数。
- string:要匹配的字符串,必选参数。
- maxsplit:分割的最大次数
- flags:标志位。
import re
result = re.split(r"\s+", "hello world")
print(result) # ['hello', 'world']
在这个例子中,正则表达式 pattern 是 “\s+”,要分割的字符串是 “hello world”,“\s+” 表示匹配一个或多个空格。re.split() 方法将字符串按照正则表达式进行分割,并返回一个列表,列表中的每个元素都是分割后的子串。
re.sub()
re.sub()
方法用于在字符串中查找正则表达式匹配的子串,并将其替换为指定的字符串。re.sub() 方法返回替换后的字符串。
re.sub(pattern, repl, string, count=0, flags=0)
- pattern:匹配的正则表达式,必选参数。
- repl:想要替换成的内容,必选参数。
- string:要匹配的字符串,必选参数。
- count:替换的次数,默认替换所有匹配到的结果;可选参数,默认为 0,为 0 时表示替换所有的匹配项。
- flags:标志位。
import re
# 将空格替换为-
result = re.sub(r"\s+", "-", "hello world")
print(result) # 'hello-world'
text = "A股全面注册制下蓝筹股盛宴能否延续?"
# 将蓝筹股替换为绩优股
result = re.sub("蓝筹股", "绩优股", text)
print(result) # 输出结果:"A股全面注册制下绩优股盛宴能否延续。"
# 将问号去掉
result = re.sub("?", "", text)
print(result)
# 输出结果:"A股全面注册制下蓝筹股盛宴能否延续"
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)