什么是正则表达式
基本说来,正则表达式是一种用来描述一定数量文本的模式。Regex代表Regular Express。我们使用一种自定义的模式来匹配一定数量的文本,并从中提取所需数据。如同window的通配符,如:.txt查找所有txt文件。就被解释成任意字符。
python中的正则表达式大致分为以下几部分:
- 元字符
- 模式
- re 内置对象用法
所有关于正则表达式的操作都使用 python 标准库中的 re 模块。
Python中的re模块
import re # 导入re模块
dir(re) # 查看re模块的方法和属性
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', '
S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '__all__', '__builtins_
_', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__ver
sion__', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_loc
ale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall
', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_pa
rse', 'sub', 'subn', 'template']
一、常见的元字符及用法
元字符 | 表述 | 表达式示例 | 完整匹配的字符串 |
---|---|---|---|
. | 匹配任意字符(不包括换行符\n) | a.c | abc |
\ | 转义字符,使跟在其后的字符将失去作为特殊元字符的含义例如\.只能匹配.,不能再匹配任意字符 | a.c | a.c |
[...] | 字符集,一个字符的集合,可匹配其中任意一个字符 | a[bcd]e | abe/ace/ade |
预定义字符(可以写在字符集[...]) | |||
\d | 匹配一个数字 [0-9] | a\dc | a1c |
\D | 匹配非数字 [^0-9]|[^\d] | a\Dz | ajz/a z/a*z/... |
\s | 匹配任意空白字符 [<空格> \t\n\r\f\v] | a\sc | a c/a\t/a\n/... |
\S | 匹配非空白字符[^ \t\n\r\f\v]]|[^\s] | a\Sc | axc/a>c/a水c/... |
\w | 匹配数字、字母、下划线中任意一个字符[a-zA-Z0-9_] | a\wc | aac/aZc/a3c/a_c |
\W | 匹配非数字、字母、下划线中的任意字符 [^a-zA-Z0-9_] | a\Wc | a c/a得c/a+c/... |
数量词(用在字符或(...)之后) | |||
* | 匹配前一个元字符0到多次 | abc* | ab/abcccc |
+ | 匹配前一个元字符1到多次 | abc+ | abc/abccc |
? | 匹配前一个元字符0到1次 | goo? | goo/go |
{m} | 匹配前一个元字符m次 | a{3} | aaa |
{m,n} | 匹配前一个元字符m到n次 | [0-9]{2,5} | 11/1111/11111 |
*?/+?/??/{m,n}? | 使*?/+?/??/{m,n}?变成非贪婪模式 | 示例参照下文 | |
边界匹配(不消耗待匹配字符串中的字符) | |||
^ | 匹配开始位置,多行模式下匹配每一行的开始 | ^Dear | Dear |
[^x] | 匹配除了x以外的任意字符 | [^abcd] | a |
$ | 匹配结束位置,多行模式下匹配每一行的结束 | .*sh$ | wddefsh |
\b | 匹配一个单词边界,匹配\w和\W之间的单词也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”(与\B相反) | a\b!ac | a!ac |
\B | 匹配非单词边界 [^\b] “er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er” | a\Bss | ass |
\A | 匹配字符串开始位置,忽略多行模式 | \ADear | Dear |
\Z | 匹配字符串结束位置,忽略多行模式 | .*ar\Z | ar/sffar |
逻辑分组 | |||
| | 代表左右表达式任意匹配 “或” 他总是先匹配 |左边的表达式,一旦满足条件则直接跳过右边的条件 如果|没有在()则他的范围是整个表达式 | abc|def | abc/def |
(...) | 分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值 | ([0-9]{3})f(oo l u)bar | 234foobar/012fubar |
(?P<name>...) | 分组的命名模式,取此分组中的内容时可以使用索引也可以使用name | (?P<id>abd){2} | abdabd |
\<number> | 引用<name>的分组匹配到的字符串 | (\d)abd\1 | 1abd1/4abd4 |
(?P=name) | 分组的引用模式,可在同一个正则表达式用引用前面命名过的正则 | (?P<id>\d)abc(?P=id) | 1abc1/4abc4 |
特殊构造(不作为分组) | |||
(?iLmsux) | 分组中可以设置模式,iLmsux之中的每个字符代表一个模式,只能用在正则表达式的开头用法参见 模式 1 | (?abc) | AbC |
(?:...) | 分组的不捕获模式,计算索引时会跳过这个分组 | (?:abc){2} | abcabc |
(?#...) | 注释,不影响正则表达式其它部分 | abc(?#coment)123 | abc123 |
(?=...) | 之后的字符串内容需要匹配表达式才能成功匹配。不消耗字符串内容 | a(?=\d) | a后面是数字 |
(?!...) | 之后的字符串内容需要不匹配表达式才能成功匹配。不消耗字符串内容。 | a(?!\d) | a后面不能是数字 |
(?<=...) | 之前的字符创内容需要匹配表达式才能成功匹配。不消耗字符串内容 | (?<=\d)a | 前面是数字的a |
(?<!...) | 之前的字符创内容需要不匹配表达式才能成功匹配。不消耗字符串内容 | (?!=\d)a | 前面不是数字的a |
(?(id/name)yes | no) 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则 | (\d)abc(?1)\d|abc) | 1abc2/abcabc |
\number | 匹配和前面索引为number的分组捕获到的内容一样的字符串 |
重复与贪婪重复和惰性重复
重复的含义是指重复匹配满足某一匹配模式的文本。
如例中(匹配ip)的’?’号就是一个重复的例子,它的含义是某一匹配模式,至多出现一次。以下列出一些重复的标示:
- * :星号,重复任意多次,如:\w*,代表任意字母,数字,下划线,汉字出现任意多次
- + :加号:至少出现一次,如:\d+,代表任意数字至少出现一次
- ? :问好:至多出现一次(出现一次或则不出现),如:\s?,代表空白字符出现0或则1次
- {n}:n代表任意数字,如:.{5},代表任意字符出现5次
- {n,}:n代表任意数字,如:\d{5,},代表任意数字出现5到多次
- {n,m}:n,m代表任意数字,如:\d{5,10},代表任意数字出现5到10次
1)re.match("[A-Z][a-z]*","Liujianhong ")
re.match("[A-Za-z]*","LiuJianhong ")
re.match("[A-Z][a-z]*","LiuJianhong ")
2)re.match("[a-zA-Z_]+[\w_]*","LiuJianhong3 ")
3)re.match("[0-9]?[\d]","1")
re.match("[0-9]?[\d]","111")
4)re.match("\w{5}","1sadfasdf11")
5)re.match("\w{5,}","1sadfasdf11")
6)re.match("\w{5,9}","1sadfasdf11")
re.match(".*\\bliu\\b","i is liu fas fsa5 662 2a") # 注意为什么使用点
re.match(r".*\bliu\b","i is liu fas fsa5 662 2a") #结果同上
贪婪与惰性匹配
首先看一个正则表达式例子:“<.>”
这个正则表达式将匹配以’<’开头,’>’结尾中间任意次任意字符,
如:<br/>,<div/>,</script>等。
当如果用该正则表达式去匹配<div>hello world</div>的话被匹配出的文本就是<div>hello world</div>,因为默认情况下正则表达式是贪婪匹配。正则表达式引擎或默认情况下将默认搜索最后一个匹配锚点。所以本例中的最后匹配锚点是</div>的>而不是<div>的>。这便是贪婪匹配。
既然明白有贪婪匹配,就必然需知惰性匹配
以上为上面这个正则表达式例子稍作改动:<.?>,我们在*后面加上一个问号便告诉引擎按照惰性匹配的方式进行搜索,使用这个正则表达式匹配<div>hello world</div>得到的结果会有两个,一个是<div>另一个是</div>。因为我们没有限定开头和结尾。
字符集
字符集:[A-Za-z0-9],匹配一个字符,这个字符是A-Za-z0-9中的任意一个
分歧
分歧:(a|b)*,a或则b出现任意多次
反义:
代码/语法 | 说明 |
---|---|
\W | <u>匹配任意不是字母,数字,下划线,汉字的字符</u> |
\S | <u>匹配任意不是空白符的字符</u> |
\D | <u>匹配任意非数字的字符</u> |
\B | <u>匹配不是单词开头或结束的位置</u> |
[^x] | <u>匹配除了x以外的任意字符</u> |
[^aeiou] | <u>匹配除了aeiou这几个字母以外的任意字符</u> |
[^ab]+ | 非a和b出现至少一次 |
分组
正则表达式的分组以()小括号进行标示,
re.match("100|[1-9][0-9]|[0-9]","2") # 匹配100以内的数
re.match("100|[1-9]?\d$","2")
re.match("\d+(183|192|168)\s","452183 ")
re.match("\d+(183|192|168)\s","452183 ").group()
re.match("\d+(183|192|168)\s","452183 ").group(1) #注意当输入1的结果
re.match("\d+(183|192|168)\.(li|wang|liu)","452168.wang").group(2)
re.match("(.*)-(\d+)","0931-5912872 ").group(2) #小括号的使用场景,特别方便
re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>","<a>liujianhong</a>") #看似正确,其实Error
re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>","<a>liujianhong</html>") #这个就是漏洞
re.match(r"<([a-zA-Z] *)>\w*</ \1>","<a>liujianhong</html>") #此时\1表示第一个括号中的值
re.match("<([a-zA-Z] *)>\w*</ \\1>","<a>liujianhong</html>") #这样也行
常用正则表达式
功能 | 语法 | 表述 |
---|---|---|
用户名 | /^[a-z0-9_-]{3,16}$/ | 只能包含小写字母、数字、_、-(至少3位,最多16位) |
密码 | /^[a-z0-9_-]{6,18}$/ | 只能包含小写字母、数字、-、_(至少3位,最多18位) |
十六进制值 | /^#?([a-f0-9]{6}|[a-f0-9]{3})$/ | 以“#”开头(也可无)6位或3位 |
电子邮箱 | /^([a-z0-9_.-]+)@([\da-z.-]+).([a-z.]{2,6})$/ | |
/^[a-z\d]+(.[a-z\d]+)*@(\da-z?)+(.{1,2}[a-z]+)+$/ | ||
URL | /^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-])/?$/ | |
IP 地址 | r"/((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)//^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ | |
HTML 标签 | /<([a-z]+)([<]+)(?:>(.)</\1>|\s+/>)$/ | |
删除代码\注释 | (?<!http:|\S)//.*$ | |
Unicode编码中的汉字范围 | /^[\u2E80-\u9FFF]+$/ |