前言
正则表达式就是用来匹配字符的,shell中的grep、python中的re模块。基本都是类似的。
正则表达式
1- 字符类
正则表达式中的字符除了表示普通字符本身,还有一些特殊用法的字符,称为元字符。
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
* | 匹配0个或多个的表达式。 |
+ | 匹配1个或多个的表达式。 |
? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
{ } | 量词 |
| | 或。a|b 匹配a或b |
\ | 转移字符 |
() | 匹配括号内的表达式,也表示一个组 |
[ ] | 定义字符类 |
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
1.1- 开始结束字符^ $
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
str = "hello world"
p = r'^hello world$'
match = re.search(p, str)
print(match.group())
1.2- 字符类 []、^、预定义字符
模式 | 描述 |
---|---|
^ | 取反 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[ ] | 字符类 |
* | 匹配0个或多个的表达式。 |
+ | 匹配1个或多个的表达式。 |
? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
{ } | 量词 |
| | 或。a|b 匹配a或b |
\ | 转移字符 |
() | 匹配括号内的表达式,也表示一个组 |
[ ] | 定义字符类 |
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
1.2.1- 字符集[]
用于匹配[]中的字符集,当其中任意一个出现,则匹配成功,每次只匹配字符集中的一个。
a- 单/多个字符
#!/usr/bin/python
import re
str = "this is python or Python"
p = r'[pP]ython'
match = re.search(p, str)
if match is not None:
print(match.group()) #匹配python
b- 区间
[a-z]、[0-9]等可以用于匹配字母、数字,也是每次只匹配字符集中的一个字符。
#!/usr/bin/python
import re
#str = "this is python or Python"
str = "num:12345678"
p = r'[1-5]'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配1
1.2.2- 取反^
#!/usr/bin/python
import re
#str = "this is python or Python"
str = "num:12345678"
p = r'[^0-9]'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配n
1.2.3- 预定义字符
我们可以用[0-9]、[a-z]匹配数字、字母,但是python提供了一系列预定义的特殊字符代替这些(shell中也有)
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
\1...\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
#!/usr/bin/python
import re
str = "num:12345678"
p = r'[\d]'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配1
1.3- 量词
前面我们使用[0-9]匹配一个数字,如果我们相匹配多个数字可以用量词。
^ | 取反 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
* | 匹配0个或多个的表达式。 |
+ | 匹配1个或多个的表达式。 |
? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
{ n} | 出现n次 |
{n,m} | 出现n-m次 |
{n, } | 出现不少于n次 |
1.3.1- 普通使用
例如我们想匹配电话号码
#!/usr/bin/python
import re
str = "phone num:025-12345678"
p = r'(\d{3})-(\d{7})'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配025-1234567
1.3.2- 贪婪
使用量词*{n,m}等会匹配更多的字符:
#!/usr/bin/python
import re
str = "phone num:123025-12345678"
p = r'(\d{3})-(\d{7,8})'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配025-12345678
如果想匹配最少的字符可以在数量字符后加上?,表示尽可能少匹配
#!/usr/bin/python
import re
str = "phone num:123025-12345678"
p = r'(\d{3})-(\d{7,8}?)'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配025-1234567
1.4- 分组()
() | 分组 |
(?P<分组名>xxx) | 分组名 |
\xxx | 引用分组 |
(?:xxx) | 非捕获分组 |
1.4.1- 简单使用
将需要匹配的字符放到()中,打印时可以使用group(xx),打印第xx个分组内容。group()打印匹配的所有内容
以前面的匹配电话号为例:
#!/usr/bin/python
import re
str = "phone num:123025-12345678"
p = r'(\d{3})-(\d{7})'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配025-1234567
print(match.group(1))#匹配025
print(match.group(2))#匹配1234567
1.4.2- 分组名命 (?P<分组名>xxx)
?P<分组名>,来标记分组名字
注意:打印时,名字用字符''包起来
#!/usr/bin/python
import re
str = "phone num:123025-12345678"
p = r'(?P<area_num>\d{3})-(?P<phone_num>\d{7})'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配025-1234567
print(match.group('area_num'))#匹配025
print(match.group('phone_num'))#匹配1234567
1.4.3- 反向引用分组 \xxx
对于匹配的字符,需要第一个分组内容和第二个分组内容一样,可以使用引用分组。语法\xxx,xxx位你想用引用的分组编号,编号从1开始。
#!/usr/bin/python
import re
str = "<a>hello<a>"
str_2 = "<a>hello<b>"
p = r'<(\w)+>hello<\1>'
match = re.search(p, str)
if match is not None:
print(match.group())#匹配<a>hello<a>
match_2 = re.search(p, str_2)
if match_2 is not None:
print(match.group())#不匹配
else:
print("not match match_2")
1.4.4- 非捕获分组(?:xxx)
我们捕获只分组中的内容。如果我们想要捕获包含分组的内容需要用到非捕获分组。不好描述,看例子:
正常分组匹配:
#!/usr/bin/python
import re
str = "1.jpg 2.jpg 3.jpg 4.png"
p = r'\w(\.jpg)'
match = re.findall(p, str)
print(match) #匹配['.jpg', '.jpg', '.jpg']
非捕获分组匹配:
#!/usr/bin/python
import re
str = "1.jpg 2.jpg 3.jpg 4.png"
p = r'\w(?:\.jpg)'
match = re.findall(p, str)
print(match) #匹配['1.jpg', '2.jpg', '3.jpg']
1.5- re模块
前面我们已经接触到了re.search、re,findall接口。接下来系统介绍下
1.5.1- re.match、re.search
a- 这两个接口都用于搜索,返回第一个匹配到的内容。
b- 只是re.match从开头匹配,开头没有返回不匹配;re.search从字符串任意位置匹配。
c- 此外这两个接口返回match类型数据,使用xxx.group()打印匹配的内容。
#!/usr/bin/python
import re
str = "hello world"
p = r'world'
match = re.match(p, str)
if match is not None:
print(match.group())
else:
print("re.match not match")
match = re.search(p, str)
if match is not None:
print(match.group())
else:
print("re.search not match")
1.5.2- re.findall、re.finditer
a- 这两个接口用于在字符中匹配,只要匹配到就保存到结果里(返回多个)。也就是说假如字符中由3个部分匹配到,结果中就保存3个内容。这是和re.search、re.match明显不同的(只返回第一个)。
b- re.findall返回的数据类型位list,re.finditer返回的数据类型位iter
#!/usr/bin/python
import re
str = "i like python or Python"
p = r'[pP]ython'
match = re.findall(p, str)
if match is not None:
print(match) #打印['python', 'Python']
else:
print("re.findall not match")
match = re.finditer(p, str)
if match is not None:
print(match)
for item in match: #打印python Python
print(item.group())
else:
print("re.finditer not match")
注意:re.finditer匹配结果必须用for循环打印,每个结果为match类型,用xxx.group()打印。
1.5.3- 其他
分割字符:re.split()
替换字符:re.sub()
1.5.4- 编译正则表达式
我们可以将正则关系式使用re.compile编译一下,返回regx格式结果。匹配时使用regx.search等接口匹配结果。没什么可讲的,直接写个例子理解下。
#!/usr/bin/python
import re
str = "i like python or Python"
p = r'[pP]ython'
regx = re.compile(p)
match = regx.findall(str)
if match is not None:
print(match) #打印['python', 'Python']
else:
print("re.findall not match")
1.5.5- 正则表达式关键字
在使用re.xxx接口时,可以使用flag。主要有:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符。 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
其中re.S、re.M、re.I比较重要。
示例:
a- re.S
感觉示例不明显,用findall,就不用加re.S了
#!/usr/bin/python
import re
str = "hello\nworld"
p = r'.+'
match = re.search(p,str)
if match is not None:
print(match.group()) #打印hello
else:
print("re.search not match")
match = re.search(p,str, re.S)
if match is not None:
print(match.group()) #打印hello world
else:
print("re.search not match")
b- re.M
#!/usr/bin/python
import re
str = "hello\nworld"
p = r'^world'
match = re.search(p,str)
if match is not None:
print(match.group())
else:
print("re.search not match")#不匹配
match = re.search(p,str, re.M)
if match is not None:
print(match.group()) #打印 world
else:
print("re.search not match")
总结:
a- re.match、re.search匹配结果为match类型,使用xxx.group打印
b- re.findall匹配结果为list
c- re.finditer匹配结果为iter类型,使用for循环遍历打印,遍历的类型为match,使用xxx.group()打印
参考
《python从小白到大牛》--关东升
python官方手册:https://docs.python.org/zh-cn/3/library/re.html#re.findall
菜鸟教程python3:https://www.runoob.com/python3/python3-reg-expressions.html