第十六章 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()

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

>>> 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()

例如:判断字符串开头是否匹配字符
>>> 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, ...])

    >>> 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‘

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

    >>> m = re.match(r"(..)+", "a1b2c3")    
    >>> m.group(1)
    ‘c3‘

2)groups([default])

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

    >>> m = re.match(r"(\d+)\.(\d+)", "24.1632")    
    >>> m.groups()
    (‘24‘, ‘1632‘)

3)groupdict([default])

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

    >>> 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()

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

    >>> email = "[email protected]_126.com"    
    >>> m = re.search(r"_126", email)
    >>> email[:m.start()] + email[m.end():]
    ‘[email protected]‘

5)span()

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

    >>> email = "[email protected]_126.com"    
    >>> m = re.search(r"_126", email)
    >>> m.span()
    (8, 12)

6)pos和endpos

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

    >>> email = "[email protected]_126.com"    
    >>> m = re.search(r"_126", email)
    >>> m.pos
    0
    >>> m.endpos
    16

16.2.3 search()

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

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

>>> m = re.search(r"c", "abcdefc")
>>> m.group()
‘c‘
>>> m.span()
(2, 3)

16.2.4 split()

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

>>> m = re.split(r"\d+", "a1b2c3")       
>>> m
[‘a‘, ‘b‘, ‘c‘, ‘‘]
16.2.4 sub()

例如:替换2016

>>> m = re.sub(r"\d+", "2017", "the year 2016")
>>> m
‘the year 2017‘

例如:repl作为一个函数

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

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

16.2.5 findall()和finditer()

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

>>> text = "a1b2c3"
>>> re.findall(r‘\d+‘, text)
[‘1‘, ‘2‘, ‘3‘]
>>> for m in re.finditer(r‘\d+‘, text):
...   print m.group()
...
1
2
3

16.2.6 原始字符串符号"r"

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

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

>>> 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 贪婪和非贪婪匹配

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

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

# 贪婪匹配
>>> 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中的:

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

2)(?!...)

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

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

>>> re.findall(r"re(?!g)", "A regular expression") 
[‘re‘]
>>> re.findall(r"re(?!g).{5}", "A regular expression")
[‘ression‘]

3)(?<=...)

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

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

>>> re.findall(r"(?<=\w)re", "A regular expression")
[‘re‘]
>>> re.findall(r"(?<=\w)re.", "A regular expression")       
[‘res‘]

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

4)(?<!...)

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

只想匹配开头的re:

>>> re.findall(r"(?<!\w)re", "A regular expression") 
[‘re‘]
>>> re.findall(r"(?<!\w)re.", "A regular expression")
[‘reg‘]

16.4 修饰符

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

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

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

Python正则表达式参考:https://docs.python.org/2/library/re.html

时间: 2024-07-30 03:27:15

第十六章 Python正则表达式的相关文章

第十五章 shell正则表达式

第十五章 shell正则表达式 见图片 Shell正则表达式 正则表达式的分类 基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs) 扩展的正则表达式(Extended Regular Expression 又叫Extended RegEx 简称EREs) Perl的正则表达式(Perl Regular Expression 又叫Perl RegEx 简称PREs) 基本组成部分 正则表达式的基本组成部分. 正则表达式 描述 示例 Bas

第十六章 在文件中搜索文本工具:grep命令 和egrep命令

第十六章 在文件中搜索文本工具:grep命令 和egrep命令 名词解释 grep(global search regular expression(RE)and print out the line,全面搜索正则表达式并把行打印出来) grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. 选项 - -a :不要忽略二进制数据 - -A <显示行数>:除了显示符合范本样式的那一行之外,并显示该行之后的内容. - -b :在显示符合范本样式的那一行之外,并显示该行

C Primer Plus (第五版) 第十六章 C预处理器和C库 编程练习

第十六章 C预处理器和C库 开发一个包含您需要使用的预处理器定义的头文件 //max.h  #ifndef _MAX_H_     #define _MAX_H_     #define MAX(X, Y) ((X)>(Y)?(X):(Y)) #endif 2.两个数的调和平均数可用如下方法得到:首先对两数的倒数取平均值,最后再取倒数.使用#define指令定义一个宏"函数"执行这个运算.编写一个简单的程序测试该宏. #include <stdio.h> #defin

CSS3秘笈复习:十三章&amp;十四章&amp;十五章&amp;十六章&amp;十七章

第十三章 1.在使用浮动时,源代码的顺序非常重要.浮动元素的HTML必须处在要包围它的元素的HTML之前. 2.清楚浮动: (1).在外围div的底部添加一个清除元素:clear属性可以防止元素包围浮动元素.关键字:left.right或both. (2).浮动外围元素:让包含浮动元素的<div>也浮动.选择这种方法一定要在浮动容器后面的任何元素中添加一个clear属性,确保浮动元素落到容器的下方. (3).利用overflow : hidden.另一种常见的方法是在外围的样式中添加以下属性:

第十六章 多态性

相同函数名具有多态性: ①  译时的多态(由函数名来调用时体现):重载:同类,不同参 ②  运行时的多态(用指向不同类的指针来调用): 覆盖:  不同类,同参,基类有virtual(由指针的类型来决定,体现了多态性) 隐藏:①不同类,同参,基类无virtual②不同类,不同参(不论有无virtual)(由指针来决定,不能体现多态性) 1.  为什么要使用多重继承 多态性可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数.C++多态性是通过虚函数(virtual)来实现的. 2.

《Java并发编程实战》第十六章 Java内存模型 读书笔记

Java内存模型是保障多线程安全的根基,这里仅仅是认识型的理解总结并未深入研究. 一.什么是内存模型,为什么需要它 Java内存模型(Java Memory Model)并发相关的安全发布,同步策略的规范.一致性等都来自于JMM. 1 平台的内存模型 在架构定义的内存模型中将告诉应用程序可以从内存系统中获得怎样的保证,此外还定义了一些特殊的指令(称为内存栅栏或栅栏),当需要共享数据时,这些指令就能实现额外的存储协调保证. JVM通过在适当的位置上插入内存栅栏来屏蔽在JVM与底层平台内存模型之间的

Gradle 1.12 翻译——第十六章. 使用文件

有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com/1.12/userguide/userguide.html 本文原创,转载请注明出处:http://blog.csdn.net/maosidiaoxian/article/details/41113353 关于我对Gradle的翻译,以Github上的项目及http://gradledoc.qin

Gradle 1.12用户指南翻译——第三十六章. Sonar Runner 插件

本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://github.com/msdx/gradledoc/tree/1.12. 直接浏览双语版的文档请访问: http://gradledoc.qiniudn.com/1.12/userguide/userguide.html. 另外,Android 手机用户可通过我写的一个

《构建之法》第十六章读后感更正

第十六章IT行业的创新 1.关于灵感.灵光闪现固然重要,很多伟大的发明依靠的就是灵光一现的基础,但是灵光闪现的前提是个人的思考,长时间的思考.完成这一灵光的基础是不断的尝试,提高自己的技术.这样才会将自己的灵光变成一个实物而不是空想. 2.关于喜好.并不是人人都喜欢创新,因为创新本来就是个长耗时又难以被认可的东西.创新有需要考虑的因素有许多,个人.面子.优先级等等,现在人们更多的是支持在原有材料技术上的"线性发展"--扩充功能等. 3.关于想法.人们接受的并不是好的想法而是他们所需要的