超详细:正则表达式从入门到入门

本文章首发于公众号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 匹配 colorcolour
?匹配前一个字符出现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股全面注册制下蓝筹股盛宴能否延续"
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入门到精通正则表达式学习入

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值