什么是正则#
正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为元字符))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。
作用#
1 快速高效的查找与分析字符串 2 进行有规律查找比对字符串,也叫:模式匹配 3 具有查找、比对、匹配、替换、插入、添加、删除等能力。
字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如我们编写爬虫收集数据,首先都得到网页源码,但是我们要如何提取有效数据呢,这时候我们就需要使用正则表达式来进行匹配了
Python中的正则—— re模块#
正则表达式中,使用 \
表示转义,这与原生的Python 行为是一致的,但是使用正则匹配时,应先进行Python原生字符串的转义,之后进行re
的转义。
s = 'I\'m monkey!' x = re.compile('I\'m monkey!') # ret = x.findall(s) print(ret) x = re.compile('I\\\'m monkey!') # 在表示正则的字符中 两个// 表示 正则表达式中的一个/ 因为要先经过Python字符转义 会少一个 ret = x.findall(s) print(ret) # 两次结果一致
re中的符号和法则#
正则表达式由特殊的语法,这个表达式也称为 模式字符串
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
尽可能的使用 ‘r’ 前缀表示字符串,像这样的方式 r'I'm Monkey'
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{ n} | 匹配n个前面表达式。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。 |
re{ n,} | 精确匹配n个前面表达式。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}"等价于"o+"。"o{0,}"则等价于"o*"。 |
re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
a|b | 匹配a或b |
(re) | 匹配括号内的表达式,也表示一个组 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (...), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#...) | 注释. |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。 |
(?> re) | 匹配的独立模式,省去回溯。 |
\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个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
注意:表中re指的是表达式而不是字面的re这两个字母
Python中正则表达式修饰符 - 可选标志#
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
正则表达式对象#
re.RegexObject#
re.compile() 返回 RegexObject 对象。
re.MatchObject#
group() 返回被 RE 匹配的字符串。 start()返回匹配开始的位置 nd()返回匹配结束的位置 span()返回一个元组包含匹配 (开始,结束) 的位置
举几个栗子#
匹配出河南省焦作市温县所有2000年后出生的人的身份证号
'^410825[^10]\d{3}\d{7}[0-9x]'
匹配出一篇文档中所有的div.user-info标签<div class="user-info">username:Monkey</div>
'<div class="user-info">.*</div>'
匹配出name和age
msg = 'name:monkey,age:100;' obj = re.match('name:(\w+),age:(\d+)', msg) print(obj.group(0)) # name:monkey,age:100 原始字符 print(obj.group(1)) # monkey 第一匹配 print(obj.group(2)) # 100 print(obj.groups()) # ('monkey', '100')
约束密码中必须有除下划线外的特殊字符
'.*\W+.*'
rules | meaning |
---|---|
{n,m} | 来限制匹配的长度 |
[abc] | 用来限制匹配的范围 必须是 a或b或c |
[^abc] | 不能是 a或b或c |
| | 表示或 1(1|2)0可以匹配 110 或 120 |
^表示行的开头 | ^\d表示必须以数字开头。 |
$表示行的结束 | \d$表示必须以数字结束。 |
re模常用方法#
re.match()#
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
语法#
re.match(pattern, string, flags=0) """ pattern : 匹配的正则表达式 string : 要匹配的字符串 flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见上方可选标志表格 """
例子#
print(re.match('Monkey', 'Monkey is a good boy!').span()) print(re.match('goood boy', 'Monkey is a good boy!')) # __________________________ # (0, 6) # None
re.search()#
re.search 扫描整个字符串并返回第一个成功的匹配。
语法#
re.search(pattern, string, flags=0)
import re re.search(pattern, string, flags=0) """ pattern : 匹配的正则表达式 string : 要匹配的字符串 flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见上方可选标志表格 """
例子#
import re x = re.search('monkey','monkey, monkey, _kali monkey') print(x.span()) # (0, 6)
re.compile()#
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象。
提前编译可减少多次正则匹配的运行时间
语法#
import re re.compile(pattern, flags=0) """ pattern : 匹配的正则表达式 flags : 可选标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见上方可选标志表格 """
例子#
import re msg =re.compile('<div class="good-info">(.*)</div>') ret = msg.findall('<div class="good-info">商品信息</div>') print(ret) # ['商品信息']
re.findall()#
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
match 和 search 是匹配一次 findall 匹配所有。
语法#
re.findall(pattern, string, flags=0) """ pattern : 匹配的正则表达式 string : 要匹配的字符串 flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见上方可选标志表格 """
实例#
import re ret = re.findall('my', 'my name is monkey,my phone number is xxxx') # ['my', 'my']
re.finditer()#
和 findall 类似,findall() 匹配字符串中的所有结果返回列表,finditer()返回一个迭代器。
语法#
re.finditer(pattern, string, flags=0) """ pattern : 匹配的正则表达式 string : 要匹配的字符串 flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见上方可选标志表格 """
实例#
import re ret = re.findall('my', 'my name is monkey,my phone number is xxxx') # <callable_iterator object at 0x109852518>
re.split()#
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下
语法#
re.split(pattern, string[, maxsplit=0, flags=0]) """ """
实例#
import re ret = re.split(',+', 'name:monkey,gender:male,addr:xxxxx,,,,hobby:lady') print(ret) # ['name:monkey', 'gender:male', 'addr:xxxxx', 'hobby:lady']
re.sub()#
Python 的re模块提供了re.sub用于替换字符串中的匹配项。
语法#
re.sub(pattern, repl, string, count=0, flags=0) """ pattern : 必填 模式字符串。 repl : 必填 替换的字符串对象,也可为一个函数对象。 string : 必填 要被查找替换的原始字符串。 count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 flags : 编译时用的匹配模式,数字形式 缺省为 0 """
前三个为必选参数,后两个为可选参数。
实例#
# 将所有年龄改成18岁 msg = 'name:monkey,age:100;' \ 'name:hook,age:80;' \ 'name:black,age:90;' r = re.sub(':\d+;', ':18;', msg, count=0) # name:monkey,age:18;name:hook,age:18;name:black,age:18;
分组与命名#
分组#
以括号()
包裹起来,叫一个分组。分组是可以嵌套的
msg = 'name:monkey,age:100;' r = re.match('name:(\w+),age:(\d+)', msg) print(r.groups()) # ('monkey', '100')
命名#
Django 1.x 版本的URLconf 中使用命名匹配来提取URL参数
msg = 'name:monkey,age:100;' r = re.match('name:(?P<name>\w+),age:(?P<age>\d+)', msg) print(r.groupdict()) # {'name': 'monkey', 'age': '100'}
贪婪匹配#
re.match(r'^(\d+)(0*)$', '102300').groups() ('102300', '')
正则默认是贪婪的,也就是说会尽可能多的去匹配字符。
由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。
如果希望分开匹配,那必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:
re.match(r'^(\d+)(0*)$', '102300').groups() ('1023', '00')
正则表达式一些实例 字符匹配#
re | meaning |
---|---|
python | 匹配 "python" |
[Pp]ython | 匹配 "Python" 或 "python" |
rub[ye] | 匹配 "ruby" 或 "rube" |
[aeiou] | 匹配中括号内的任意一个字母 |
[0-9] | 匹配任何数字。类似于 [0123456789] [a-z] 匹配任何小写字母 |
[A-Z] | 匹配任何大写字母 |
[a-zA-Z0-9] | 匹配任何字母及数字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了数字外的字符 |
特殊字符类
re | meaning |
---|---|
. | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。等价于 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
\W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |