Python字符串的匹配和搜索

in 互联网技术 with 0 comment  访问: 3,195 次

如果你想匹配或者搜索特定的字段的时候,如果你匹配的是相对比较简单的字符串的时候你只需要利用find()rfind()endswitch()startswitch()等类似的方法即可,示例如下:

>>> info = "My host ip address is  10.0.1.10"
>>> info == 'ip'
False
>>> info.startswith('My')
True
>>> info.endswith('0')
True
>>> info.find('d')
12

对于复杂的匹配我们就要使用正则表了,那既然用到正则的话我们就得利用re模块的方法了。为了解释正则表达式的基本使用,我们假设要匹配数字格式的字符串比如: 2018-06-27,示例如下:

>>> date1 = '2018-06-27'
>>> date2 = '2018-06-nock'
>>> import re
>>> # 简单匹配:\d+表示匹配一个或多个数字
>>> print('match yes') if re.match(r'\d+-\d+-\d+', date1) else print('match no')
match yes
>>> print('match yes') if re.match(r'\d+-\d+-\d+', date2) else print('match no')
match no

如果你想使用同一个模式去做多次匹配,那你应该先将模式字符串预先编译为模式对象,然后再去做匹配,示例如下:

>>> import re
>>> matchObject = re.compile(r'\d+/\d+/\d+')
>>> text = '07/08/2018'
>>> print('match yes') if matchObject.match(text) else print('match failed')
match yes
>>> print(matchObject.match(text))
<_sre.SRE_Match object; span=(0, 10), match='07/08/2018'>

>>> text = 'Today is 07/08/2018, PyCon starts 03/13/2013'
>>> print('match yes') if matchObject.match(text) else print('match failed')
match failed
>>> print(matchObject.match(text))    # 默认返回空
None

match()方法的查找是从头开始去做完全匹配的,如果你想查找到字符串任意位置出现的匹配模式,并且希望得到结果,你可以使用findall()去替代,示例如下:

>>> import re
>>> text = 'Today is 07/08/2018, PyCon starts 03/13/2013'
>>> matchObject = re.compile(r'\d+/\d+/\d+')
>>> matchObject.findall(text)
['07/08/2018', '03/13/2013']
>>> 

如上所示就把字符串中,你要的结果都找到了,并且默认输出是一个列表,如果没有匹配到任何内容,默认返回一个空列表。

在定义正则的时候,通常会利用括号去做捕获分组,比如:

matchObjec = = re.compile(r'(\d+)/(\d+)/(\d+)')

捕获分组之后可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来,示例如下:

>>> matchObject = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> m = matchObject.match('10/08/2018')
>>> m.group(0)
'10/08/2018'
>>> m.group(1)
'10'
>>> m.group(2)
'08'
>>> m.group(3)
'2018'
>>> m.groups()
('10', '08', '2018')
>>> month, day, year = m.groups()
>>> print(month, day, year)
10 08 2018

>>> # 查找所有匹配项
>>> text = 'Today is 07/08/2018, PyCon starts 03/13/2013'
>>> matchObject = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> matchObject.findall(text)
[('07', '08', '2018'), ('03', '13', '2013')]
>>> for month, day, year in matchObject.findall(text):
...     print('{}-{}-{}'.format(year, month, day))
...     
... 
2018-07-08
2013-03-13

findall() 方法会搜索文本并以列表形式返回所有的匹配。 如果你想以迭代方式返回匹配,可以使用 finditer()方法来代替,比如:

>>> text = 'Today is 07/08/2018, PyCon starts 03/13/2013'
>>> matchObject = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> for m in matchObject.finditer(text):
...     print(m.groups())
...     
... 
('07', '08', '2018')
('03', '13', '2013')
>>> for m in matchObject.finditer(text):
...     print(m.group())
...     
... 
07/08/2018
03/13/2013

总结

上面主要讲解了一下利用re模块进行字符串的匹配和搜索的基本用法,核心方法就是先使用re.compile()编译你想匹配的正则表达式字符串内容,然后再使用match(),findall()finditer()方法的结合使用。

当你编写正则表达式的时候,低昂对普通的做法是使用原始字符串,比如: r'(\d+)/(\d+)/(\d+)' 。这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。 如果不这样做的话,你必须使用两个反斜杠,类似 '(\\d+)/(\\d+)/(\\d+)'

需要注意的是match()方法仅仅检查字符串的开始部分。它的匹配结果有可能并不是你期望的那样精确,如果你想精确匹配,确保你的正则表达式以$结尾,就像这么这样:

>>> m = matchObject.match('10/08/2018abcd')
>>> m
<_sre.SRE_Match object; span=(0, 10), match='10/08/2018'>
>>> m.group()
'10/08/2018'

>>> matchObject = re.compile(r'(\d+)/(\d+)/(\d+)$')
>>> m = matchObject.match('10/08/2018abcd')
>>> print(type(m))
<class 'NoneType'>
>>> m = matchObject.match('10/08/2018')
>>> print(type(m))
<class '_sre.SRE_Match'>
>>> m.group()
'10/08/2018'

最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,直接使用 re 模块级别的函数。比如:

>>> text = 'Today is 07/08/2018, PyCon starts 03/13/2013'
>>> re.findall(r'(\d+)/(\d+)/(\d+)', text)
[('07', '08', '2018'), ('03', '13', '2013')]

但是需要注意的是,如果你打算做大量的匹配和搜索操作的话,最好先编译正则表达式,然后再重复使用它。 模块级别的函数会将最近编译过的模式缓存起来,因此并不会消耗太多的性能, 但是如果使用预编译模式的话,你将会减少查找和一些额外的处理损耗。

WeZan