python正则表达式详解
  正则表达式是⼀个很强⼤的字符串处理⼯具,⼏乎任何关于字符串的操作都可以使⽤正则表达式来完成,作为⼀个爬⾍⼯作者,每天和字符串打交道,正则表达式更是不可或缺的技能,正则表达式的在不同的语⾔中使⽤⽅式可能不⼀样,不过只要学会了任意⼀门语⾔的正则表达式⽤法,其他语⾔中⼤部分也只是换了个函数的名称⽽已,本质都是⼀样的。下⾯,我来介绍⼀下python中的正则表达式是怎么使⽤的。
  ⾸先,python中的正则表达式⼤致分为以下⼏部分:
1.
1. 元字符
2. 模式
3. 函数
4. re 内置对象⽤法
5. 分组⽤法
6. 环视⽤法
  所有关于正则表达式的操作都使⽤ python 标准库中的 re 模块。
⼀、元字符(参见 python 模块 re ⽂档)
.                    匹配任意字符(不包括换⾏符)
python正则表达式不包含
^                    匹配开始位置,多⾏模式下匹配每⼀⾏的开始
$                    匹配结束位置,多⾏模式下匹配每⼀⾏的结束
*                    匹配前⼀个元字符0到多次
+                    匹配前⼀个元字符1到多次
?                    匹配前⼀个元字符0到1次
{m,n}                匹配前⼀个元字符m到n次
\\                  转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符
[]                  字符集,⼀个字符的集合,可匹配其中任意⼀个字符
|                    逻辑表达式或,⽐如 a|b 代表可匹配 a 或者 b
(...)                分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值
(?iLmsux)            分组中可以设置模式,iLmsux之中的每个字符代表⼀个模式,⽤法参见模式 I
(?:...)              分组的不捕获模式,计算索引时会跳过这个分组
(?P<name>...)        分组的命名模式,取此分组中的内容时可以使⽤索引也可以使⽤name
(?P=name)            分组的引⽤模式,可在同⼀个正则表达式⽤引⽤前⾯命名过的正则
(?#...)              注释,不影响正则表达式其它部分,⽤法参见模式 I
(?=...)              顺序肯定环视,表⽰所在位置右侧能够匹配括号内正则
(?!...)              顺序否定环视,表⽰所在位置右侧不能匹配括号内正则
(?<=...)            逆序肯定环视,表⽰所在位置左侧能够匹配括号内正则
(?<!...)            逆序否定环视,表⽰所在位置左侧不能匹配括号内正则
(?(id/name)yes|no)  若前⾯指定id或name的分区匹配成功则执⾏yes处的正则,否则执⾏no处的正则
\number              匹配和前⾯索引为number的分组捕获到的内容⼀样的字符串
\A                  匹配字符串开始位置,忽略多⾏模式
\Z                  匹配字符串结束位置,忽略多⾏模式
\b                  匹配位于单词开始或结束位置的空字符串
\B                  匹配不位于单词开始或结束位置的空字符串
\d                  匹配⼀个数字,相当于 [0-9]
\D                  匹配⾮数字,相当于 [^0-9]
\s                  匹配任意空⽩字符,相当于 [ \t\n\r\f\v]
\S                  匹配⾮空⽩字符,相当于 [^ \t\n\r\f\v]
\w                  匹配数字、字母、下划线中任意⼀个字符,相当于 [a-zA-Z0-9_]
\W                  匹配⾮数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]
⼆、模式
I    IGNORECASE,忽略⼤⼩写的匹配模式, 样例如下
s = 'hello World!'
regex = repile("hello world!", re.I)
print regex.match(s).group()
#output> 'Hello World!'
#在正则表达式中指定模式以及注释
regex = repile("(?#注释)(?i)hello world!")
print regex.match(s).group()
#output> 'Hello World!'
L    LOCALE,字符集本地化。这个功能是为了⽀持多语⾔版本的字符集使⽤环境的,⽐如在转义符\w,在英⽂环境下,它代表[a-zA-Z0-9_],即所以英⽂字符和数字。如果在⼀个法语环境下使⽤,缺省设置下,不能匹配"é" 或  "ç"。加上这L选项和就可以匹配了。不过这个对于中⽂环境似乎没有什么⽤,它仍然不能匹配中⽂字符。
M    MULTILINE,多⾏模式, 改变 ^ 和 $ 的⾏为
s = '''first line
second line
third line'''
# ^
regex_start = repile("^\w+")
print regex_start.findall(s)
# output> ['first']
regex_start_m = repile("^\w+", re.M)
print regex_start_m.findall(s)
# output> ['first', 'second', 'third']
#$
regex_end = repile("\w+$")
print regex_end.findall(s)
# output> ['line']
regex_end_m = repile("\w+$", re.M)
print regex_end_m.findall(s)
# output> ['line', 'line', 'line']
S   DOTALL,此模式下 '.' 的匹配不受限制,可匹配任何字符,包括换⾏符
s = '''first line
second line
third line'''
#
regex = repile(".+")
print regex.findall(s)
# output> ['first line', 'second line', 'third line']
# re.S
regex_dotall = repile(".+", re.S)
print regex_dotall.findall(s)
# output> ['first line\nsecond line\nthird line']
X    VERBOSE,冗余模式,此模式忽略正则表达式中的空⽩和#号的注释,例如写⼀个匹配邮箱的正则表达式
email_regex = repile("[\w+\.]+@[a-zA-Z\d]+\.(com|cn)")
email_regex = repile("""[\w+\.]+  # 匹配@符前的部分
@  # @符
[a-zA-Z\d]+  # 邮箱类别
\.(com|cn)  # 邮箱后缀  """, re.X)
U    UNICODE,使⽤ \w, \W, \b, \B 这些元字符时将按照 UNICODE 定义的属性.
正则表达式的模式是可以同时使⽤多个的,在 python ⾥⾯使⽤按位或运算符 | 同时添加多个模式
如 repile('', re.I|re.M|re.S)
每个模式在 re 模块中其实就是不同的数字
print re.I
# output> 2
print re.L
# output> 4
print re.M
# output> 8
print re.S
# output> 16
print re.X
# output> 64
print re.U
# output> 32
三、函数(参见 python 模块 re ⽂档)
python 的 re 模块提供了很多⽅便的函数使你可以使⽤正则表达式来操作字符串,每种函数都有它⾃⼰的特性和使⽤场景,熟悉之后对你的⼯作会有很⼤帮助
compile(pattern, flags=0)
给定⼀个正则表达式 pattern,指定使⽤的模式 flags 默认为0 即不使⽤任何模式,然后会返回⼀个 SRE_Pattern (参见第四⼩节 re 内置对象⽤法) 对象regex = repile(".+")
print regex
# output> <_sre.SRE_Pattern object at 0x00000000026BB0B8>
这个对象可以调⽤其他函数来完成匹配,⼀般来说推荐使⽤ compile 函数预编译出⼀个正则模式之后再去使⽤,这样在后⾯的代码中可以很⽅便的复⽤它,当然⼤部分函数也可以不⽤ compile 直接使⽤,具体见 findall 函数
second line
third line'''
#
regex = repile(".+")
# 调⽤ findall 函数
print regex.findall(s)
# output> ['first line', 'second line', 'third line']
# 调⽤ search 函数
print regex.search(s).group()
# output> first lin
escape(pattern)
转义如果你需要操作的⽂本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹
配⾃⾝,⽽当这样的字符很多时,写出来的正则表达式就看起来很乱⽽且写起来也挺⿇烦的,这个时候你可以使⽤这个函数,⽤法如下
s = ".+\d123"
#
regex_str = re.escape(".+\d123")
# 查看转义后的字符
print regex_str
# output> \.\+\\d123
# 查看匹配到的结果
for g in re.findall(regex_str, s):
print g
# output> .+\d123
findall(pattern, string, flags=0)
参数 pattern 为正则表达式, string 为待操作字符串, flags 为所⽤模式,函数作⽤为在待操作字符串中寻所有匹配正则表达式的字串,返回⼀个列表,如果没有匹配到任何⼦串,返回⼀个空列表。
s = '''first line
second line
third line'''
# compile 预编译后使⽤ findall
regex = repile("\w+")
print regex.findall(s)
# output> ['first', 'line', 'second', 'line', 'third', 'line']
# 不使⽤ compile 直接使⽤ findall
print re.findall("\w+", s)
# output> ['first', 'line', 'second', 'line', 'third', 'line']
finditer(pattern, string, flags=0)
参数和作⽤与 findall ⼀样,不同之处在于 findall 返回⼀个列表, finditer 返回⼀个迭代器(参见  ),⽽且迭代器每次返回的值并不是字符串,⽽是⼀
个 SRE_Match (参见第四⼩节 re 内置对象⽤法) 对象,这个对象的具体⽤法见 match 函数。
s = '''first line
second line
third line'''
regex = repile("\w+")
print regex.finditer(s)
# output> <callable-iterator object at 0x0000000001DF3B38>
for i in regex.finditer(s):
print i
# output> <_sre.SRE_Match object at 0x0000000002B7A920>
#        <_sre.SRE_Match object at 0x0000000002B7A8B8>
#        <_sre.SRE_Match object at 0x0000000002B7A920>
#        <_sre.SRE_Match object at 0x0000000002B7A8B8>
#        <_sre.SRE_Match object at 0x0000000002B7A920>
#        <_sre.SRE_Match object at 0x0000000002B7A8B8>
match(pattern, string, flags=0)
使⽤指定正则去待操作字符串中寻可以匹配的⼦串, 返回匹配上的第⼀个字串,并且不再继续,需要注意的是 match 函数是从字符串开始处开始查的,如果开始处不匹配,则不再继续寻,返回值为⼀个 SRE_Match(参见第四⼩节 re 内置对象⽤法) 对象,不到时返回 None
s = '''first line
second line
third line'''
# compile
regex = repile("\w+")
m = regex.match(s)
print m
# output> <_sre.SRE_Match object at 0x0000000002BCA8B8>
up()
# s 的开头是 "f", 但正则中限制了开始为 i 所以不到
regex = repile("^i\w+")
print regex.match(s)
# output> None
purge()
当你在程序中使⽤ re 模块,⽆论是先使⽤ compile 还是直接使⽤⽐如 findall 来使⽤正则表达式操作⽂本,re 模块都会将正则表达式先编译⼀下,并且会将编译过后的正则表达式放到缓存中,这样下次使⽤同样的正则表达式的时候就不需要再次编译,因为编译其实是很费时的,这样可以提升效率,⽽默认缓存的正则表达式的个数是 100, 当你需要频繁使⽤少量正则表达式的时候,缓存可以提升效率,⽽使⽤的正则表达式过多时,缓存带来的优势就不明显了 (参考《》),这个函数的作⽤是清除缓存中的正则表达式,可能在你需要优化占⽤内存的时候会⽤到。
search(pattern, string, flags=0)
函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置
s = '''first line
second line
third line'''
# 需要从开始处匹配所以匹配不到
print re.match('i\w+', s)
# output> None
# 没有限制起始匹配位置
print re.search('i\w+', s)
# output> <_sre.SRE_Match object at 0x0000000002C6A920>
print re.search('i\w+', s).group()
# output> irst
split(pattern, string, maxsplit=0, flags=0)
参数 maxsplit 指定切分次数,函数使⽤给定正则表达式寻切分字符串位置,返回包含切分后⼦串的列表,如果匹配不到,则返回包含原字符串的⼀个列表
s = '''first 111 line
second 222 line
third 333 line'''
# 按照数字切分
print re.split('\d+', s)
# output> ['first ', ' line\nsecond ', ' line\nthird ', ' line']
# \.+ 匹配不到返回包含⾃⾝的列表
print re.split('\.+', s, 1)
# output> ['first 111 line\nsecond 222 line\nthird 333 line']
# maxsplit 参数
print re.split('\d+', s, 1)
# output> ['first ', ' line\nsecond 222 line\nthird 333 line']
sub(pattern, repl, string, count=0, flags=0)
替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串,  参数 count ⽤于指定最⼤替换次数
s = "the sum of 7 and 9 is [7+9]."
# 基本⽤法将⽬标替换为固定字符串
print re.sub('\[7\+9\]', '16', s)
# output> the sum of 7 and 9 is 16.
# ⾼级⽤法 1 使⽤前⾯匹配的到的内容 \1 代表 pattern 中捕获到的第⼀个分组的内容
print re.sub('\[(7)\+(9)\]', r'\2\1', s)
# output> the sum of 7 and 9 is 97.
# ⾼级⽤法 2 使⽤函数型 repl 参数, 处理匹配到的 SRE_Match 对象
def replacement(m):
p_str = m.group()
if p_str == '7':
return '77'
if p_str == '9':
return '99'
return ''
print re.sub('\d', replacement, s)
# output> the sum of 77 and 99 is [77+99].
# ⾼级⽤法 3 使⽤函数型 repl 参数, 处理匹配到的 SRE_Match 对象增加作⽤域⾃动计算
scope = {}
example_string_1 = "the sum of 7 and 9 is [7+9]."
example_string_2 = "[name = 'Mr.Gumby']Hello,[name]"
def replacement(m):
code = m.group(1)
st = ''
try:
st = str(eval(code, scope))
except SyntaxError:
exec code in scope
return st
# 解析: code='7+9'
#      str(eval(code, scope))='16'
print re.sub('\[(.+?)\]', replacement, example_string_1)
# output> the sum of 7 and 9 is 16.
# 两次替换
# 解析1: code="name = 'Mr.Gumby'"
#      eval(code)
#      raise SyntaxError
#      exec code in scope
#      在命名空间 scope 中将 "Mr.Gumby" 赋给了变量 name
# 解析2: code="name"
#      eval(name) 返回变量 name 的值 Mr.Gumby
print re.sub('\[(.+?)\]', replacement, example_string_2)
# output> Hello,Mr.Gumby
subn(pattern, repl, string, count=0, flags=0)
作⽤与函数 sub ⼀样,唯⼀不同之处在于返回值为⼀个元组,第⼀个值为替换后的字符串,第⼆个值为发⽣替换的次数
template(pattern, flags=0)
这个吧,咋⼀看和 compile 差不多,不过不⽀持 +、?、*、{}等这样的元字符,只要是需要有重复功能的元字符,就不⽀持,查了查资料,貌似没⼈知道这个函数到底是⼲嘛的...
  四、re 内置对象⽤法
SRE_Pattern    这个对象是⼀个编译后的正则表达式,编译后不仅能够复⽤和提升效率,同时也能够获得⼀些其他的关于正则表达式的信息
属性:
flags        编译时指定的模式
groupindex    以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
groups        正则表达式中分组的数量
pattern      编译时⽤的正则表达式
s = 'Hello, Mr.Gumby : 2016/10/26'
p = repile('''(?:        # 构造⼀个不捕获分组⽤于使⽤ |
(?P<name>\w+\.\w+)    # 匹配 Mr.Gumby
|    # 或
(?P<no>\s+\.\w+) # ⼀个匹配不到的命名分组
)
.*? # 匹配  :
(\d+) # 匹配 2016
''', re.X)
#
print p.flags
# output> 64
upindex
# output> {'name': 1, 'no': 2}
ups
# output> 3
print p.pattern
# output> (?:        # 构造⼀个不捕获分组⽤于使⽤ |
#              (?P<name>\w+\.\w+)    # 匹配 Mr.Gumby
#              |    # 或
#              (?P<no>\s+\.\w+) # ⼀个匹配不到的命名分组
#              )
#              .*? # 匹配  :
#              (\d+) # 匹配 2016

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。