第十六章 Python正则表达式

简介:

正则表达式在每种语言中都会有,目的就是匹配符合你预期要求的字符串。

Python正则表达式主要由re库提供,拥有了基本所有的表达式。

16.1 Python正则表达式

符号

描述

示例

. 匹配除换行符(\n)之外的任意单个字符 字符串123\n456,匹配123:1.3
^ 匹配字符串开头 abc\nxyz,匹配以abc开头的行:^abc
$ 匹配字符串结尾 abc\nxyz,匹配以xyz结束的行:xyz$
* 匹配多个 hello\nword,匹配以w开头d结尾的单词:w*d
+ 匹配1个或多个 abc\nabcc\nadf,匹配abc和abcc:ab+
匹配0个或1个 abc\nac\nadd,匹配abc或ac:a?c
[.] 匹配中括号之中的任意一个字符 abcd\nadd\nbbb,匹配abcd和add:[abc]
[ .-.] 匹配中括号中范围内的任意一个字符 abcd\nadd\nbbb,匹配abcd和add:[a-c]
[^] 匹配[^字符]之外的任意一个字符 abc\n\abb\nddd,不匹配abc和abb:[^a-c]
{n}或{n,} 匹配花括号前面字符至少n个字符 1\n\12\n123\n1234,匹配123和1234:[0-9]{3}
{n,m} 匹配花括号前面字符至少n个字符,最多m个字符 1\n\12\n123\n1234\n12345,匹配123和1234 :[0-9]{3,4}
| 匹配竖杠两边的任意一个 abc\nabd\abe,匹配abc和abd:ab(c|d)
\ 转义符,将特殊符号转成原有意义 1.2,匹配1.2:1\.2,否则112也会匹配到


特殊字符

描述

示例

\A 匹配字符串开始

与^区别是:当使用修饰符re.M匹配多行时,\A将所有字符串作为一整行处理。

abc123\nabc456,匹配abc123:\Aabc,^则都会匹配到

\Z 匹配字符串结束 与\A同理
\b 匹配字符串开始或结束(边界) abc\nabcd,匹配a开头并且c结尾字符串:\babc\b
\B 与\b相反
\d 匹配任意十进制数,等效[0-9] 1\n123\nabc,匹配1和123:[0-9],包含单个数字的都会匹配到,如果只想匹配1:\b[0-9]\b
\D 匹配任意非数字字符,等效[^0-9] 1\n12\nabc,匹配abc:[^0-9]
\s 匹配任意空白字符,等效[\t\n\r\f\v] 1\n a,注意a前面有个空格,匹配a:\s
\S 匹配任意非空白字符,等效[^\t\n\r\f\v] 1\n a\n ,匹配1和a:\S
\w 匹配任意数字和字母,等效[a-zA-Z0-9_] 1\n a\n ,匹配1和a:\w
\W 与\w相反,等效[^a-zA-Z0-9_]
\n 反向引用,n是数字,从1开始编号,表示引用第n个分组匹配的内容 ff,匹配ff:(.)\1,即"ff"


扩展正则表达式

描述

( ) 匹配小括号中正则表达式或字符。用上面\n特殊字符引用。
(?#...) 注释小括号内的内容
(?:...) 不保存匹配的分组
(?P<name>...) 命名分组,name是标识名称,默认是数字ID标识分组匹配
(?=...) 匹配后面能匹配表的达式...,称为正先行断言
(?!...) 匹配后面不能匹配的表达式...,称为负先行断言
(?<=...) 匹配前面能匹配的表达式...,称为正后发断言
(?<!...) 匹配前面不能匹配的表达式...,称为负后发断言
(?(id/name)Y/N) 如果分组提供的id或name存在,则使用Y表达式匹配,否则N表达式匹配

断言:断言就是一个条件,判断某个字符串前面或后面是否满足某种规律的字符串,不能引用。

16.2 re库

re模块有以下常用的方法:

方法

描述

re.compile(pattern, flags=0) 把正则表达式编译成一个对象
re.findall(pattern, string, flags=0) 以列表形式返回所有匹配的字符串
re.finditer(pattern, string, flags=0) 以迭代器形式返回所有匹配的字符串
re.match(pattern, string, flags=0) 匹配字符串开始,如果不匹配返回None
re.search(pattern, string, flags=0) 扫描字符串寻找匹配,如果符合返回一个匹配对象并终止匹配,否则返回None
re.split(pattern, string, maxsplit=0, flags=0) 以匹配模式作为分隔符,切分字符串为列表
re.sub(pattern, repl, string, count=0, flags=0) 字符串替换,repl替换匹配的字符串,repl可以是一个函数
re.purge() 清除正则表达式缓存

参数说明:

pattern   正则表达式

string    要匹配的字符串

flags     标志位的修饰符,用于控制表达式匹配模式

标志位的修饰符,有以下可选项:

修饰符

描述

re.DEBUG 显示关于编译正则的debug信息
re.I/re.IGNORECASE 忽略大小写
re.L/re.LOCALE 本地化匹配,影响\w,\w,\b,\B,\s和\S
re.M/re.MULTILINE 多行匹配,影响^和$
re.S/re.DOTAIL 匹配所有字符,包括换行符\n,如果没这个标志将匹配除了换行符
re.U/re.UNICODE 根据unicode字符集解析字符。影响影响\w,\w,\b,\B,\d,\D,\s和\S
re.X/re.VERBOSE 允许编写更好看、更可读的正则表达式,也可以在表达式添加注释,下面会讲到


博客地址:http://lizhenliang.blog.51cto.com

QQ群:323779636(Shell/Python运维开发群


16.2.1 re.compile()

把正则表达式编译成一个对象,方便再次调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>>  import  re
prog  =  re. compile (pattern)
result  =  prog.match(string)
等效于
result  =  re.match(pattern, string)
例如:检查字符串是否匹配
>>>  def  displaymatch(match):
...      if  match  is  None :
...          return  None
...      return  '<Match: %r, group=%r>'  %  (match.group(), match.groups())
...
>>> valid  =  re. compile (r "^[a-c1-3]{3}$" )
>>> displaymatch(valid.match( "a1b" ))    # 可用
"<Match: 'a1b', group=()>"
>>> displaymatch(valid.match( "a1b2" ))   # 不可用
>>> displaymatch(valid.match( "bbb" ))    # 可用
"<Match: 'bbb', group=()>"

16.2.1 match()

1
2
3
4
5
6
7
例如:判断字符串开头是否匹配字符
>>> m  =  re.match(r 'hello' 'hello world' )           
>>>  print  m   # 匹配到字符串开头是hello
<_sre.SRE_Match  object  at  0x7f56d5634030 >
>>> m  =  re.match(r 'world' 'hello world' )     
>>>  print  m   # 没有匹配到
None

正则对象匹配方法:

1)group([group1, ...])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> m  =  re.match(r '(\w+) (\w+)' 'hello world' )    
>>> m.group( 0 )     # 全部组匹配
'hello world'
>>> m.group( 1 )     # 第一个括号子组
'hello'
>>> m.group( 2 )     # 第二个括号子组
'world'
>>> m.group( 1 2 # 多个参数返回一个元组
( 'hello' 'world' )
通过分子重命名的名字来引用分组结果:
>>> m  =  re.match(r '(?P<first_name>\w+) (?P<last_name>\w+)' 'hello world' )    
>>> m.group( 'first_name' )
'hello'
>>> m.group( 'last_name' )
'world'
# 命名组也可以引用他们的索引
>>> m.group( 1 )
'hello'
>>> m.group( 2 )
'world'

如果一组匹配多次,只有最后一个匹配:

1
2
3
>>> m  =  re.match(r "(..)+" "a1b2c3" )    
>>> m.group( 1 )
'c3'

2)groups([default])

返回一个元组包含所有子组的匹配。

1
2
3
>>> m  =  re.match(r "(\d+)\.(\d+)" "24.1632" )    
>>> m.groups()
( '24' '1632' )

3)groupdict([default])

返回子组名字作为键,匹配结果作为值的字典。

1
2
3
>>> m  =  re.match(r "(?P<first_name>\w+) (?P<last_name>\w+)" "hello world" )    
>>> m.groupdict()
{ 'first_name' 'hello' 'last_name' 'world' }

4)start()和end()

例如:去掉邮件地址的某字符

1
2
3
4
>>> email  =  "tony@163_126.com"    
>>> m  =  re.search(r "_126" , email)
>>> email[:m.start()]  +  email[m.end():]
'tony@163.com'

5)span()

以列表形式返回匹配索引开始和结束值:

1
2
3
4
>>> email  =  "tony@163_126.com"    
>>> m  =  re.search(r "_126" , email)
>>> m.span()
( 8 12 )

6)pos和endpos

返回字符串开始和结束索引值:

1
2
3
4
5
6
>>> email  =  "tony@163_126.com"    
>>> m  =  re.search(r "_126" , email)
>>> m.pos
0
>>> m.endpos
16

16.2.3 search()

search()方法也具备match()方法的正则对象匹配方法,区别是search()匹配到第一个后就返回并终止匹配。

例如:匹配第一个结果就返回

1
2
3
4
5
>>> m  =  re.search(r "c" "abcdefc" )
>>> m.group()
'c'
>>> m.span()
( 2 3 )

16.2.4 split()

例如:以数字作为分隔符拆分字符串

1
2
3
4
>>> m  =  re.split(r "\d+" "a1b2c3" )       
>>> m
[ 'a' 'b' 'c' , '']
16.2 . 4  sub()

例如:替换2016

1
2
3
>>> m  =  re.sub(r "\d+" "2017" "the year 2016" )
>>> m
'the year 2017'

例如:repl作为一个函数

1
2
3
4
5
>>>  def  repl(m):                         
...    return  str ( int (m.group( 'v' ))  *  2 )     
...
>>> re.sub(r '(?P<v>\d+)' , repl,  "123abc" )
'246abc'

函数返回必须是一个字符串。

16.2.5 findall()和finditer()

例如:得到所有匹配的数字

1
2
3
4
5
6
7
8
9
>>> text  =  "a1b2c3"
>>> re.findall(r '\d+' , text)
[ '1' '2' '3' ]
>>>  for  in  re.finditer(r '\d+' , text):
...    print  m.group()
...
1
2
3

16.2.6 原始字符串符号"r"

上面所看到的(r"\d+")其中的r代表原始字符串,没有它,每个反斜杠'\'都必须再加一个反斜杠来转义它。

例如,下面两行代码功能上是相同的:

1
2
3
4
5
6
7
8
9
10
11
>>> m  =  re.match(r "\W(.)\1\W" " ff " )
>>> m.group()
' ff '
>>> m  =  re.match( "\\W(.)\\1\\W" " ff " )
>>> m.group()
' ff '
>>> m  =  re.match( "\W(.)\1\W" " ff " )   
>>> m.group()
Traceback (most recent call last):
   File  "<stdin>" , line  1 in  <module>
AttributeError:  'NoneType'  object  has no attribute  'group'

\W匹配第一个和最后一个空字符,(.)匹配第一个f,\1引用前面(.)匹配的结果(还是f),即是r"ff"

16.3 贪婪和非贪婪匹配

贪婪模式:尽可能最多匹配

非贪婪模式,尽可能最少匹配,一般在量词(*、+)后面加个问号就是非贪婪模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 贪婪匹配
>>> re.findall(r "<div>.*</div>" "<div>a</div><div>b</div><div>c</div>" )
[ '<div>a</div><div>b</div><div>c</div>' ]
# 非贪婪匹配
>>> re.findall(r "<div>.*?</div>" "<div>a</div><div>b</div><div>c</div>" )
[ '<div>a</div>' '<div>b</div>' '<div>c</div>' ]
>>> re.findall(r "a(\d+)" "a123b" )     
[ '123' ]
>>> re.findall(r "a(\d+?)" "a123b" )
[ '1' ]
# 如果右边有限定,非贪婪失效
>>> re.findall(r "a(\d+)b" "a123b" )   
[ '123' ]
>>> re.findall(r "a(\d+?)b" "a123b" )  
[ '123' ]

贪婪匹配是尽可能的向右匹配,直到字符串结束。

非贪婪匹配是匹配满足后就结束。

16.3 了解扩展表达式

以一个字符串来学习断言的用法:"A regular expression "

1)(?=...)

正先行断言,匹配后面能匹配的表达式。

有两个re字符串,只想匹配regular中的:

1
2
3
4
5
>>> re.findall(r "..(?=gular)" "A regular expression"
[ 're' ]
# 再向后匹配几个字符说明匹配的regular中的。下面都会说明下,不再注释
>>> re.findall(r "(?=gular).{5}" "A regular expression" )
[ 'gular' ]

2)(?!...)

负先行断言,匹配后面不能匹配表达式。

只想匹配expression中的re字符串,排除掉regular单词:

1
2
3
4
>>> re.findall(r "re(?!g)" "A regular expression"
[ 're' ]
>>> re.findall(r "re(?!g).{5}" "A regular expression" )
[ 'ression' ]

3)(?<=...)

正向后行断言,匹配前面能匹配表达式。

只想匹配单词里的re,排除开头的re:

1
2
3
4
>>> re.findall(r "(?<=\w)re" "A regular expression" )
[ 're' ]
>>> re.findall(r "(?<=\w)re." "A regular expression" )       
[ 'res' ]

在re前面有一个或多个字符,所以叫后行断言,正则匹配是从前向后,当遇到断言时,会再向字符串前端检测已扫描的字符,相对于扫描方向是向后的。

4)(?<!...)

负向后行断言,匹配前面不能匹配的表达式。

只想匹配开头的re:

1
2
3
4
>>> re.findall(r "(?<!\w)re" "A regular expression"
[ 're' ]
>>> re.findall(r "(?<!\w)re." "A regular expression" )
[ 'reg' ]

16.4 修饰符

re.VERBOSE上面说明可能你还不太明白,怎么个更加可读呢,这就来看看,下面两个正则编译等效:

1
2
3
4
>>> a  =  re. compile (r """\d +  # the integral part
...                    \.    # the decimal point
...                    \d *  # some fractional digits""" , re.X)
>>> b  =  re. compile (r "\d+\.\d*" )

当你写的正则很长的时候,可以添加注释。



本文转自 李振良OK 51CTO博客,原文链接:http://blog.51cto.com/lizhenliang/1877675,如需转载请自行联系原作者

相关文章
|
数据采集 监控 数据安全/隐私保护
Python正则表达式:用"模式密码"解锁复杂字符串
正则表达式是处理字符串的强大工具,本文以Python的`re`模块为核心,详细解析其原理与应用。从基础语法如字符类、量词到进阶技巧如贪婪匹配与预定义字符集,结合日志分析、数据清洗及网络爬虫等实战场景,展示正则表达式的强大功能。同时探讨性能优化策略(如预编译)和常见错误解决方案,帮助开发者高效掌握这一“瑞士军刀”。最后提醒,合理使用正则表达式,避免过度复杂化,追求简洁优雅的代码风格。
345 0
|
Python
"揭秘!Python如何运用神秘的正则表达式,轻松穿梭于网页迷宫,一键抓取隐藏链接?"
【8月更文挑战第21天】Python凭借其强大的编程能力,在数据抓取和网页解析领域表现出高效与灵活。通过结合requests库进行网页请求及正则表达式进行复杂文本模式匹配,可轻松提取网页信息。本示例展示如何使用Python和正则表达式解析网页链接。首先确保已安装requests库,可通过`pip install requests`安装。接着,利用requests获取网页内容,并使用正则表达式提取所有`&lt;a&gt;`标签的`href`属性。
313 0
|
Python
在Python中,可以使用内置的`re`模块来处理正则表达式
在Python中,可以使用内置的`re`模块来处理正则表达式
396 5
|
数据采集 Web App开发 iOS开发
如何使用 Python 语言的正则表达式进行网页数据的爬取?
使用 Python 进行网页数据爬取的步骤包括:1. 安装必要库(requests、re、bs4);2. 发送 HTTP 请求获取网页内容;3. 使用正则表达式提取数据;4. 数据清洗和处理;5. 循环遍历多个页面。通过这些步骤,可以高效地从网页中提取所需信息。
|
Python
Python 正则表达式高级应用指南
正则表达式是文本模式匹配的强大工具,Python 的 `re` 模块支持其操作。本文介绍正则表达式的高级应用,包括复杂模式匹配(如邮箱、电话号码)、分组与提取、替换操作、多行匹配以及贪婪与非贪婪模式的区别。通过示例代码展示了如何灵活运用这些技巧解决实际问题。
290 7
|
数据安全/隐私保护 Python
Python实用正则表达式归纳
Python实用正则表达式归纳
375 3
|
Python
【收藏备用】Python正则表达式的7个实用技巧
【收藏备用】Python正则表达式的7个实用技巧
255 1
|
索引 Python
30天拿下Python之正则表达式
30天拿下Python之正则表达式
189 1
|
数据采集 Python
Python正则表达式提取车牌号
Python正则表达式提取车牌号
528 1
|
安全 数据安全/隐私保护 Python
python中的正则表达式
python中的正则表达式