微信公众号:码农充电站pro
个人主页:https://codeshellme.github.io
0,什么是正则表达式
正则表达式
(Regular Expression
简写为Regex
),又称为规则表达式
,它是一种强大的文本匹配模式,其用于在字符串中查找匹配
符合特定规则的子串。
正则表达式是独立于编程语言
而存在的,它并不依赖于某种编程语言。只要一种编程语言实现了正则表达式引擎
,那么这种编程语言,就具备了正则表达式模式匹配的功能。每种工具
或编程语言
对正则表达式的实现,虽有细节上的不同,但基本的使用是相同的。
正则表达式的基本工作原理如下:
1,正则表达式的由来
1956 年,美国数学家Stephen Kleene
在两位神经生理学家(Warren McCulloch
和 Walter Pitts
)的早期工作的基础上,发表了一篇标题为神经网事件的表示法
的论文,由此引入了正则表达式的概念。
之后,Unix 之父Ken Thompson
把这一成果应用于计算搜索算法
的一些早期研究。随后,他将这一符号系统应用于Unix 系统
中的 qed 编辑器
,这是正则表达式的第一个实用程序。
此后,正则表达式被广泛的应用于类Unix 系统的工具中,如 grep
,perl
等。
2,正则表达式工具
RegexBuddy 是一个很不错的软件。
Regexr 是一个在线工具。
3,正则表达式语法
正则表达式由一些普通字符
(比如英文字母,数字)和元字符
(代表特定含义)组成。
正则表达式作为一个字符模板,在字符串中匹配一个或多个符合特定规则的子串。
3.1,元字符
元字符
就是包含特定含义的字符。如果想匹配这些元字符
,需要使用转义字符 进行转义。
下表是一些常用的元字符:
字符 | 含义 |
---|---|
|
转义字符,常用于转义元字符 |
. |
匹配除换行符
之外的任何单字符 |
$ |
匹配字符串的结尾位置 |
^ |
匹配字符串的开始位置 。当写在中括号[] 内时,表示不匹配该中括号 中的字符集合 |
[^xy] |
匹配非x ,非y 字符 |
() |
被小括号包含的多个字符,将作为一整个字符 |
(pattern) |
写在小括号() 内的表达式,表示一个分组 ,用于提取内容 |
(?:pattern) |
只表示一个分组 ,不提取内容 |
[] |
被中括号包含的多个字符,这多个字符的关系是逻辑或 的关系 |
[xyz] |
字符集合,匹配x 或y 或z |
[0-9] |
匹配0 到9 之间的数字 |
[a-z] |
匹配a 到z 之间的字符 |
[^a-z] |
匹配不在a 到z 范围内的任意字符 |
| |
写在两个字符之间,代表逻辑或 的关系 |
x|y |
匹配x 或 y |
|
匹配一个单词边界 |
B |
匹配非单词边界 |
d |
匹配一个数字字符,等价于[0-9] |
D |
匹配一个非数字字符,等价于[^0-9] |
s |
匹配任何空白字符 ,包括空格 、制表符 等 |
S |
匹配任何非空白字符 |
w |
匹配字母 、数字 、下划线 ,等价于[A-Za-z0-9_] |
W |
匹配非字母 、非数字 、非下划线 ,等价于[^A-Za-z0-9_] |
f |
匹配换页符 |
|
匹配换行符 |
|
匹配回车符 |
|
匹配制表符 |
v |
匹配垂直制表符 |
3.2,限定符
限定符
也属于元字符,用来限定一个子表达式
出现的次数。
字符 | 含义 |
---|---|
* |
匹配前面的子表达式零次 或多次 |
+ |
匹配前面的子表达式一次 或多次 |
? |
匹配前面的子表达式零次 或一次 |
{n} |
匹配前面的子表达式n次 |
{n,} |
匹配前面的子表达式至少n次 |
{n,m} |
匹配前面的子表达式n 到m 次 |
4,正则表达式示例
我们逐个介绍一下每种元字符的使用方式,下面的例子我们都使用RegexBuddy
软件来演示。
4.1,转义字符
转义字符用来对一些元字符进行转义,使这些元字符失去其特定的含义,只表示一个普通的字符。
比如我们想匹配字符串aaa^bbb
中的a^b
子串,我们需要用模式a^b
来匹配,^
之前需要加一个转义字符。
4.2,元字符.
元字符.
可匹配任意(除了换行符
)的单字符,意思就是.
可以代表任意(除了换行符
)的单字符。
4.3,开始位置^
与结束位置$
符号^
表示匹配的子串在行首
,符号$
表示匹配的子串在行尾
。
匹配行首
匹配行尾
行首行尾
4.4,逻辑或|
符号|
写在两个子表达式
之间表示逻辑或
的意思。
例如模式串ab|cd
,匹配ab
或 cd
。
4.5,限定符
限定符
用于限定一个子表达式
出现的次数
,一共6 种,这里给出一些示例。
符号*
模式串ab*c
,表示字符a
和c
之间需要出现0 次
或多次
字符b
。
符号+
模式串ab+c
,表示字符a
和c
之间需要出现1 次
或多次
字符b
,即至少出现1次
字符b
。
符号?
模式串ab?c
,表示字符a
和c
之间需要出现0 次
或1次
字符b
。
符号{n}
和{n,}
和{n,m}
ab{3}c
:符号b 出现的次数必须是3
ab{3,}c
:符号b 出现的次数必须大于等于3
ab{3,5}c
:符号b 出现的次数必须在3
和5
之间,包括3
和5
4.6,字符簇[]
写在中括号[]
内的多个字符代表逻辑或
的意思。
模式串a[bef]c
,表示a
和c
中间的字符必须是b
或e
或f
。
当符号^
写在中括号[]
内时,表示逻辑非
的意思。
模式串a[^bef]c
,表示a
和c
中间的字符不能是b
或e
或f
。
符号-
写在中括号[]
,表示范围
的意思:
示例 | 含义 |
---|---|
[a-z] |
表示a 到z 之间的任意字符 |
[A-Z] |
表示A 到Z 之间的任意字符 |
[0-9] |
表示0 到9 之间的任意数字,含义同d |
[^0-9] |
表示任意非数字 ,含义同D |
[A-Za-z0-9_] |
表示任意字母 ,数字 或下划线 ,含义同w |
[^A-Za-z0-9_] |
表示任意非字母 ,非数字 ,非下划线 ,含义同W |
[ f
] |
表示任意的空白字符 ,含义同s |
[^ f
] |
表示任意的非空白字符 ,含义同S |
4.7,字符组合()
写在小括号()
中的多个字符,会被看成一个整体。
4.8,单词边界
与B
符号 是指一个
单词边界
,比如空白字符和标点符号等。
符号B
表示非单词边界
。
5,贪婪与非贪婪模式
正则表达式中贪婪
的意思就是贪多
,意思就是正则在匹配的过程中,总是去匹配尽可能多
的字符,符号?
可以将贪婪
转换为非贪婪
。
6,在Python
中使用正则
Python 中提供了re
模块,用于支持正则表达式功能。
在python
中一般在表达式前加r
,表示原始字符
,不用考虑转义的问题。例如r'abc'
。
下面打开python
终端:
- 首先引入模块,
import re
help(re)
可查看re 模块帮助手册dir(re)
可查看其支持的属性和方法
>>> python `打开python 终端`
_____________________________________________
Python 2.7.17 (default, Nov 7 2019, 10:07:09)
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import re # 引入re 模块
>>>
>>> help(re) # 查看帮助手册
>>>
>>> dir(re) # 查看re 支持的属性和方法
6.1,re 模块常用方法
方法 | 含义 |
---|---|
match |
用于匹配表达式 |
search |
查找匹配项 |
findall |
查找所有的匹配项 |
compile |
编译正则表达式 |
详细解释:
match(pattern, string, flags=0)
Try to apply the pattern at the start of the string, returning
a match object, or None if no match was found.
search(pattern, string, flags=0)
Scan through string looking for a match to the pattern, returning
a match object, or None if no match was found.
findall(pattern, string, flags=0)
Return a list of all non-overlapping matches in the string.
If one or more groups are present in the pattern, return a
list of groups; this will be a list of tuples if the pattern
has more than one group.
Empty matches are included in the result.
compile(pattern, flags=0)
Compile a regular expression pattern, returning a pattern object.
可以看到,每个方法中都有一个flag
参数,它表示匹配模式
,默认值为0
,表示普通模式。
flag
参数的值有以下几种选择,可以使用符号|
连接多种选择:
`I/IGNORECASE` Perform case-insensitive matching.
`L/LOCALE` Make w, W, , B, dependent on the current locale.
`M/MULTILINE` "^" matches the beginning of lines (after a newline)
as well as the string.
"$" matches the end of lines (before a newline) as well
as the end of the string.
`S/DOTALL` "." matches any character at all, including the newline.
`X/VERBOSE` Ignore whitespace and comments for nicer looking RE's.
`U/UNICODE` Make w, W, , B, dependent on the Unicode locale.
6.2,match 方法
re.match
尝试从字符串的起始位置
开始匹配:
- 成功:返回
SRE_Match
对象 - 失败:返回
None
>>> m = re.match(r'abc', 'abcde')
>>> print m # 匹配成功
<_sre.SRE_Match object at 0x7f91544cff80>
>>>
>>>
>>> m = re.match(r'abc', 'fabcde')
>>> print m # `fabcde` 不是以`abc` 开头,匹配失败
None
>>>
6.3,search 方法
re.search
扫描整个字符串,直到找到第一个
成功的匹配:
- 成功:返回
SRE_Match
对象 - 失败:返回
None
>>> m = re.search(r'abc', 'abcde')
>>> print m # 匹配成功
<_sre.SRE_Match object at 0x7f91544cff80>
>>>
>>> m = re.search(r'abc', 'fabcde')
>>> print m # 匹配成功
<_sre.SRE_Match object at 0x7f9154521b90>
6.4,findall 方法
re.findall
在字符串中查找所有
匹配的子串:
- 成功:返回一个列表
- 失败:返回
空列表[]
>>> re.findall(r'abc', 'fabcdeabc')
['abc', 'abc'] # 找到两个`abc` 子串
>>>
>>> re.findall(r'abce', 'fabcdeabc')
[] # 没找到子串
>>>
6.5,compile 方法
在使用正则时,re
模块会先将正则表达式
进行编译
,然后才会去字符串中匹配。
如果一个正则表达式
会使用很多次,我们可以使用re.compile
方法对表达式进行预编译
,这样就不会在每次用到这个表达式时都进行编译,有助于提高效率。
该方法返回一个SRE_Pattern
对象,该对象又包含match
,search
,findall
等方法,使用方法如下:
>>> reg = re.compile(r'abc') # 编译
>>>
>>> type(reg)
<type '_sre.SRE_Pattern'>
>>>
>>> reg.findall('fabcdeabc') # 找到两个
['abc', 'abc']
>>>
>>> reg.match('fabcdeabc') # 没有匹配上
>>>
>>> reg.search('fabcdeabc') # 匹配上
<_sre.SRE_Match object at 0x7f9154521b90>
6.6,SRE_Match 对象
SRE_Match
对象用于获取分组,写在小括号()
内的表达式是一个分组。
>>> # 正则中包含两个分组
>>> m = re.match(r'(d*)-(w*)', '123-abc-')
>>> m
<_sre.SRE_Match object at 0x7f91544e0ae0>
>>> m.group(0) # 获取整个匹配的串,同 m.group()
'123-abc'
>>> m.group(1) # 获取第一个分组
'123'
>>> m.group(2) # 获取第二个分组
'abc'
>>>
6.7,match,search,findall 比较
我们来看下match
,search
,findall
三个方法的异同点:
- match:必须从字符串的开头匹配,只会有一个匹配项,返回结果是
SRE_Match
对象 - search:扫描整个字符串,直到匹配到第一个为止,只会有一个匹配项,返回结果是
SRE_Match
对象 - findall:扫描整个字符串,返回所有的匹配项,返回结果是一个字符串列表
(完。)
欢迎关注作者公众号,获取更过技术干货。