网络爬虫笔记【6】 Python 中的正则表达式模块与应用

python3 内置的 re 模块,包含了正则表达式的操作集。 re 模块的一般使用步骤如下:

  1. 编译正则表达式,即使用 compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象。
  2. 对目标字符串进行匹配,即通过 Pattern 对象提供的一些列方法对文本进行匹配查找,获得匹配结果(Match 对象)
  3. 提取结果信息,即使用 Match 对象提供的属性和方法获得信息,还可以根据需要进行其他操作。

compile 函数

Compile 函数用于编译正则表达式,生成一个 Pattern 对象。一般使用形式如下:

import re
pattern = re.compile(一个正则表达式)

成功编译并构造 pattern 对象后,就可以使用 pattern 对象方法查找、替换、统计目标字符串中与正则表达式匹配的子字符串了。pattern 对象可调用的方法有:

  • match 方法:从起始位置开始查找,一次匹配
  • search
  • fullmatch
  • sub
  • subn
  • split
  • purge
  • template
  • escape
  • error
  • findall
  • finditer 事实上,这些函数不仅是对象可调用的,也是可以使用 re 模块直接调用的。

match 方法

match 方法用于在字符串起始位置进行模式匹配,若匹配则返回 Match 对象,否则返回 None。

match(pattern, string, flags=0) 
# method of re module Try to apply the pattern at the start of the string, returning a match object, or None if no match was found. 

match(string=None, pos=0, endpos=None, pattern=None) 
# method of Pattern instance Matches zero or more characters at the beginning of the string.

下面举例说明:

''' re 模块 compile 方法与 match 方法示例'''
import re

text1 = 'sdaksfhksjdfnkfsjldhfsk234sfd65s1df55s3sdf4156sd4et489t74t6'
text2 = 'SDakufasdakru9013rgp2k;.,/,.;.t2,445,3/4l,63;lk,3;l,43'

print('运行结果:\n')
pattern = re.compile('sdak')

# <_sre.SRE_Match object; span=(0, 4), match='sdak'>
match = pattern.match(text1)
print(match)
print('---'*10)

# None
match = pattern.match(text2)
print(match)
print('---'*10)

# <_sre.SRE_Match object; span=(7, 11), match='sdak'>
match = pattern.match(text2, pos = 7)
print(match)

if match:
    # sdak
    print(match.group())
print('---'*10)

# re.IGNORECASE 忽略大小写
pattern = re.compile('sdak', flags = re.IGNORECASE)
match = pattern.match(text2)

if match:
    # SDak
    print(match.group())
print('---'*10)
运行结果:

<_sre.SRE_Match object; span=(0, 4), match='sdak'>
------------------------------
None
------------------------------
<_sre.SRE_Match object; span=(7, 11), match='sdak'>
sdak
------------------------------
SDak
------------------------------

Match 对象

match 对象是正则表达式匹配目标字符串后返回的结果对象。它可调用以下方法:

  • group([group1, …])方法,用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
  • start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
  • end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
  • span([group]) 方法返回 (start(group), end(group))。
import re

text = 'wxhh1234@qq.com中文QQ邮箱'

# 定义正则表达式,匹配目标字符串中的电子邮箱
regexstr = '\w+@\w+\.[a-z]+'

# 将正则表达式编译成 Pattern 对象
pattern = re.compile(regexstr)

# 匹配
match = pattern.match(text)

if match:
    print(match.group())
    print(match.start())
    print(match.end())
    print(match.span())
运行结果:

wxhh1234@qq.com
0
15
(0, 15)

search 方法

Search 方法用于查找字符串的任何位置,它只返回从左到右第一个匹配的结果,而不是查找所有匹配的结果。

# search 方法示例

import re

text = 'one12twothree34four'

# 设置正则表达式查找第一个数字串
regexstr = '\d+'
pattern = re.compile(regexstr)

# match 方法是从第一个字符开始匹配,这里第一个字符不是数字,则返回 None
match = pattern.match(text)

print('pattern.match:')
print(match)
    
print('---'*10)
# search 方法是从左往右检索,返回第一个匹配到的结果,这里返回 12
match = pattern.search(text)
print('pattern.search:')

if match:
    print(match.group())
    print(match.span())
运行结果:

pattern.match:
None
------------------------------
pattern.search:
12
(3, 5)

findall 与 finditer 方法

上面的 match 和 search 方法都是一次性匹配,而有时需要获取目标字符串中所有匹配的结果,这需要使用 findall 或 finditer 方法。使用形式如下:

findall(string[, pos[, endpos]])
其中,string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。

finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果,但是它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。

简单讲就是,findall 会把所有结果一次性返回,finditer 得用循环一个一个返回

import re

text = '你好wxhh1234@qq.com中文QQ邮箱'

# 定义正则表达式,匹配字符串中的中文
regexstr = u'[\u4e00-\u9fa5]+'

pattern = re.compile(regexstr)
matchlist = pattern.findall(text)

if matchlist:
    print(matchlist)
    
else:
    print('None')

print('---'*10)

matchiter = pattern.finditer(text)
if matchiter:
    print(matchiter)
    for m in matchiter:
        print('Match result:{}, postion: {}'.format(m.group(),m.span()))
else:
    print('None')
运行结果:

['你好', '中文', '邮箱']
------------------------------
<callable_iterator object at 0x00000165B601D630>
Match result:你好, postion: (0, 2)
Match result:中文, postion: (17, 19)
Match result:邮箱, postion: (21, 23)

split 方法

split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次数,不指定将全部分割。
import re

text = 'a,b;;c d  ,;e'
# 正则表达式,字符串前加 r,表示该字符串是 raw string。
regexstr = r'[\,\;\s]+'

pattern = re.compile(regexstr)
match = pattern.split(text)

if match:
    print(match)
else:
    print('None')
运行结果:

['a', 'b', 'c', 'd', 'e']

sub 方法

sub 方法用于替换。它的使用形式如下:

sub(repl, string[, count])
  • repl 可以是字符串也可以是一个函数
    • 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
    • 如果 repl 是函数,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
  • count 用于指定最多替换次数,不指定时全部替换。
import re

# 设置模式:两个英文字符或数字的分组,中间用空格隔开
text = 'Hello 123, Hello 456'
regexstr = r'(\w+) (\w+)'
repl = 'Hello World'
pattern = re.compile(regexstr)

# 使用 'Hello World' 替换 'Hello 123' 和 'Hello 456'
res = pattern.sub(repl,text)
print(res)
print('---'*10)

# 引用分组
repl = r'\2 \1'
# regexstr 第一个括号里匹配到的是 \1 ,第二个括号里匹配到的是 \2
res = pattern.sub(repl,text)
print(res)
print('---'*10)

# 指定替换次数
def func(m):
    return ('hi' + ' ' + m.group(2))

print(pattern.sub(func,text))
print(pattern.sub(func,text,1))
运行结果:

Hello World, Hello World
------------------------------
123 Hello, 456 Hello
------------------------------
hi 123, hi 456
hi 123, Hello 456

贪婪模式与非贪婪模式

  • 贪婪模式,指的是整个表达式匹配成功的前提下,尽可能多的匹配(使用 * ),python 里数量词默认是贪婪的;
  • 非贪婪模式,指的是整个表达式匹配成功的前提下,尽可能少的匹配(使用 *? )
# demo 1

import re

text = 'abbbbbbbbbbbbccccc'
regexStr1 = 'ab*'
regexStr2 = 'ab*?'

pattern = re.compile(regexStr1)
match = pattern.match(text)
print('贪婪模式:' + match.group())

print('---'*10)

pattern = re.compile(regexStr2)
match = pattern.match(text)
print('非贪婪模式:' + match.group())
运行结果:

贪婪模式:abbbbbbbbbbbb
------------------------------
非贪婪模式:a
# demo 2

import re

text = 'aa<div>test1</div>bb<div>test2</div>cc'
regexStr1 = '<div>.*</div>'
regexStr2 = '<div>.*?</div>'

pattern = re.compile(regexStr1)
m = pattern.search(text)
print(m.group())

print('---'*10)

pattern = re.compile(regexStr2)
m = pattern.search(text)
print(m.group())
运行结果:

<div>test1</div>bb<div>test2</div>
------------------------------
<div>test1</div>
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页