码迷,mamicode.com
首页 > 编程语言 > 详细

python-正则表达式

时间:2020-01-26 23:55:47      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:dal   pil   error:   一个   并保存   创建   max   说明   特征   

1 正则表达式

正则表达式(RE)是一些由字符和特殊字符组成的字符串,它们描述了这些字符和字符的某种重复方式,因此能按照某种模式匹配一个有相似特征的字符串的集合,因此能按某种模式匹配一系类有相似特征的字符串。

Python通过标准库re模块支持正则表达式。

说明一下术语“匹配”和“搜索”的区别:

Python专门术语中,有两种主要方法完成匹配:搜索和匹配。搜索:即在字符串任意部分中搜索匹配的模式。匹配:判断一个字符能否从开始处全部或部分的匹配某个模式。搜索通过search()函数或方法实现,匹配调用match()函数或方法实现。我们说模式的时候,使用的是术语“匹配”。

1.1 正则表达式使用的特殊符号和字符

记号

说明

正则表达式样例

literal

匹配字符串的值

foo

re1/re2

匹配正则表达式re1或re2

foo|bar

.

匹配任意字符(换行符除外)

b.b

^

匹配字符串的开始

^Dear

$

匹配字符串的结尾

/bin/*sh$

*

匹配前面出现的正则表达式零次或多次

[A-Za-z0-9]*

+

匹配前面出现的正则表达式出现一次或多次

[a-z]+\.com

?

匹配前面出现的正则表达式零次或一次

goo?

{N}

匹配前面出现的正则表达式N

[0-9]{3}

{M,N}

匹配重复出现M次到N次的正则表达式

[0-9]{5,9}

[…]

匹配字符组里出现的任意一个字符

[aeiou]

[.,x-y,.]

匹配从字符x到字符中的任意一个字符

[0-9],[A-Za-z]

[^…]

不匹配此字符集中出现的任意一个字符,包括某一范围的字符(如果在此字符集中出现)

[^aeiou],[^A-Za-z0-9]

(*|+|?|{})?

用于上面出现的任何“非贪婪”。版本重复匹配次数符号

.*?[a-z]

(…)

匹配封闭括号中正则表达式(RE),并保存为子组

([0-9]{3})?,f(oo|u)bar

特殊字符

\d

匹配任何数字,和[0-9]一样,(\D是\d的反义,任何非数符字)

data\d+.txt

\w

匹配任何数字字母字符,和[A-Za-z0-9_]相同,(\W是\w的反义)

[A-Za-z_]\w+

\s

匹配任何空白符,和[\n\t\r\v\f]相同。(\S是\s的反义)

of\sthe

\b

匹配单词边界。(\B是\b的反义)

\bThe\b

\nn

匹配已保存的子组

prince:\16

\c

逐一匹配特殊字符c(即:取消它的特殊含义,按字面匹配)

\.,\\, \*

\A(\Z)

匹配字符串的起始(结束)

\ADear

(1)用管道符号(|)匹配多个正则表达式模式

管道符号(|),表示一个或操作,它的意思是选择被管道符号分割的多个不同的正则表达式中的一个。

(2)匹配任意一个单个的字符(.)

点符号或句点(.)符号匹配除换行符(NEWLINE)外的任意一个单个字符(Python的正则表达式有一个编译标识[S or DOTALL]),该标识能去掉这一限制,使(.)      在匹配时包括换行符。无论是字母、数字、不包括“\n”的空白符、可打印的字符、还是非打印字符,或是一个符号,点(.)都可以匹配它们。

(3)从字符串的开头或结尾或单词边界开始匹配(^ $ \b \B)

^或\A:用于从字符串的开头开始匹配一个模式。

如果想匹配这两个字符中的任何一个(或全部),就必须用反斜线进行转义。

\b或\B:用来匹配单词边界,\b匹配的模式是一个单词边界(一定在一个单词的开头,不论这个单词的前面是有字符,还是没有字符),\B只匹配出现在一个单词中间的模式(不在单词边界上的字符)。

(4)创建字符类([])

使用方括号的正则表达式会匹配方括号里的任意一个字符。

(5)指定范围(-)和否定(^)

方括号里的一对字符中间的连字符(-)用来表示一个字符的范围。例如:z.[0-9]

如果左方括号后第一个字符是上箭头符号(^),就表示不匹配指定字符集里的任意字符。例如:[^aeiou]

(6)使用闭包操作符(*,+,?,{})实现多次出现/重复匹配

*:匹配它左边那个正则表达式出现零次或零次以上的情况。

+:匹配它左边那个正则表达式至少出现一次的情况。

?:匹配它左边那个正则表达式出现零次或一次的情况。

{N}:匹配N次出现。

{M,N}:匹配M次到N次出现。

(7)特殊字符表示

\d:0-9范围内的十进制数。

\w:整个字符数字的字符集,相当于“A-Za-z0-9_”。

\s:表示空白字符。

这些特殊字符的大写形式表示不匹配。

(8)用圆括号(())组建组

一对圆括号(())和正则表达式使用实现的功能有:1.对正则表达式进行分组;2.匹配子组。

使用圆括号匹配的子串会被保存到一个子组。这些字组可以在同一次匹配或搜索中被重复调用。

1.2 正则表达式和Python语言

1.2.1 re模块:核心函数和方法

常用的函数和方法:

函数/方法

描述

模块的函数

compile(pattern, flags=0)

对正则表达式模式pattern进行编译,flags是可选标识符,并返回一个regex对象(已编译的正则表达式对象)。

re模块的函数和regex对象的方法

match(pattern, string, flags=0)

尝试用正则表达式pattern匹配字符串string,flags是可选标识符,如果匹配成功,则返回一个匹配对象,否则返回None

search(pattern, string, flags=0)

在字符串string中搜索正则表达式模式pattern的第一次出现,flags是可选标识符,如果匹配成功,则返回一个匹配对象,否则返回None。

findall(pattern, string, [,flags])

在字符串string中搜索正则表达式模式pattern的所有(非重复)出现,返回一个匹配对象的列表。

finditer(pattern, string [,flags])

和findall()相同,但返回的不是列表而是迭代器;对于每个匹配,该迭代器返回一个匹配对象。

split(pattern, string, max=0)

根据正则表达式pattern中的分隔符把字符string分割为一个列表,返回成功匹配的列表,最多分割max次(默认是分割所有匹配的地方)。

sub(pattern, repl, string, max=0)

把字符串中所有匹配正则表达式pattern的地方替换成字符串repl,如果max的值没有给出,则对所有匹配的地方进行替换。

匹配对象的方法

group(num=0)

返回全部匹配对象(或指定编号是num的子组)

groups()

返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元祖)。

RE编译(何时应该使用compile函数?)

在模式匹配之前,正则表达式模式必须先被编译成regex对象,由于正则表达式在执行过程中被多次用于比较,建议先对它做预编译。re.compile()函数提供了此功能。

1.2.2 匹配对象和group()、groups()方法

在处理正则表达式中,出regex对象外,还有一种对象类型-匹配对象,通过match()函数和search()函数被成功调用后返回。匹配对象有两个主要方法:group()和groups()。

group():或返回所有匹配对象或根据要求返回某个特定子组。

groups():返回一个包含唯一或所有子组的元组。

1.2.3 用match()匹配字符串

match():从字符串开头开始对模式进行匹配,如果匹配成功,返回一个匹配对象,如果失败,返回None。匹配对象的group()方法可以用来显示那个成功的匹配。

 1 m = re.match(foo, foo)
 2 >>> if m is not None: 
 3 ...     m.group()    
 4 ... 
 5 foo
 6 >>> m
 7 <_sre.SRE_Match object at 0x7f4e059a9648>
 8 >>> m = re.match(foo, food on table) 
 9 >>> m.group()
10 foo

1.2.4 search()在一个字符串中查找一个模式

search():检查参数字符串任意位置的地方给定正则表达式的匹配情况,如果搜索到成功的匹配,会返回一个匹配对象,否则返回None。

1 >>> m = re.match(foo, seafood)
2 >>> m.group()
3 Traceback (most recent call last):
4   File "<stdin>", line 1, in <module>
5 AttributeError: NoneType object has no attribute group
6 >>> m = re.search(foo, seafood).group()
7 >>> m
8 foo

1.2.5 匹配多个字符串(|)

 1 >>> bt = bat|bet|bit
 2 >>> m = re.match(bt, bat)
 3 >>> m
 4 <_sre.SRE_Match object at 0x7f4e059a9ac0>
 5 >>> m.group()
 6 bat
 7 >>> m = re.match(bt, bit)
 8 >>> m.group()              
 9 bit
10 >>> m = re.match(bt, bet)
11 >>> m.group()              
12 bet

1.2.6 匹配任意单个字符(.)

句点是不能匹配换行符或非字符(即空字符)的。

 1 >>> m = re.match(anyend, bend)
 2 >>> if m is not None: m.group()   
 3 ... 
 4 bend
 5 >>> m = re.match(anyend, \nend) 
 6 >>> if m is not None: m.group()   
 7 ... 
 8 >>> m = re.match(anyend, end)
 9 >>> if m is not None: m.group()
10 ... 
11 >>> m = re.match(anyend, the end)
12 >>> 
13 >>> if m is not None: m.group()    
14 ... 
15 >>>
16 >>> patt314 = 3.14
17 >>> pi_patt = 3\.14
18 >>> m = re.match(pi_patt, 3.14)
19 >>> if m is not None:m.group()
20 ... 
21 3.14
22 >>> m = re.match(patt314, 3014)    
23 >>> if m is not None:m.group()   
24 ... 
25 3014
26 >>> m = re.match(patt314, 3.14)
27 >>> if m is not None:m.group()   
28 ... 
29 3.14
30 >>>

1.2.7 创建字符合集([])

 1 >>> m = re.match([cr][23][dp][o2], c3po)
 2 >>> if m is not None:m.group()              
 3 ... 
 4 c3po
 5 >>> m = re.match([cr][23][dp][o2], c2po)
 6 >>> 
 7 >>> if m is not None:m.group()              
 8 ... 
 9 c2po
10 >>> m = re.match(r2d2|c3po, c2po)                   
11 >>> 
12 >>> if m is not None:m.group()       
13 ... 
14 >>> m = re.match(r2d2|c3po, r2po)
15 >>> if m is not None:m.group()       
16 ... 
17 >>> m = re.match(r2d2|c3po, r2d2)
18 >>> 
19 >>> if m is not None:m.group()       
20 ... 
21 r2d2
22 >>>

1.2.8 重复、特殊字符和子组

例如下面的例子,表达式容许“.com”前面有一个或两个名字:

1 >>> patt = \w+@(\w+\.)?\w+\.com 
2 >>> re.match(patt, nobody@xxx.com).group()
3 nobody@xxx.com

接着修改,允许任意数量的子域存在。

1 >>> patt = \w+@(\w+\.)*\w+\.com 
2 >>> re.match(patt, nobody@xxx.yyy.zzz.com).group() 
3 nobody@xxx.yyy.zzz.com

分别提取包含字母或数字的部分或仅含有数字的部分。

1 >>> m = re.match((\w\w\w)-(\d\d\d), abc-123) 
2 >>> m.group()
3 abc-123
4 >>> m.group(1) 
5 abc
6 >>> m.group(2) 
7 123
8 >>> m.groups() 
9 (abc, 123)

group()通常用来显示所有匹配部分,也可以用来获取个别匹配的子组,groups()方法获得一个包含所有匹配子组的元组。

 1 >>> m = re.match(ab, ab) 
 2 >>> m.group()
 3 ab
 4 >>> m.groups() 
 5 ()
 6 >>> m = re.match((ab), ab) 
 7 >>> m.group()  
 8 ab
 9 >>> m.group(1) 
10 ab
11 >>> m.groups() 
12 (ab,)
13 >>> m = re.match((a)(b), ab) 
14 >>> m.group()  
15 ab
16 >>> m.group(1) 
17 a
18 >>> m.group(2) 
19 b
20 >>> m.groups() 
21 (a, b)
22 >>> m = re.match((a(b)), ab) 
23 >>> m.group()  
24 ab
25 >>> m.group(1) 
26 ab
27 >>> m.group(2) 
28 b
29 >>> m.groups() 
30 (ab, b)

1.2.9 从字符串的开头或结尾匹配及在单词边界上的匹配

这些是锚点性正则表达式,这些锚点性正则表达式主要用于搜素而不是匹配,因为match()总是从字符串的开头进行匹配的。

 1 >>> m = re.search(^The, The end)  #在开头
 2 >>> if m is not None:m.group()
 3 ... 
 4 The
 5 >>> m = re.search(^The, end. The) 
 6 >>> if m is not None:m.group()        
 7 ... 
 8 >>> m = re.search(r\bthe, bite the dog)  #在词边界
 9 >>> if m is not None:m.group()
10 ... 
11 the
12 >>> m = re.search(r\bthe, bitethe dog)  
13 >>> if m is not None:m.group()
14 ... 
15 >>> m = re.search(r\Bthe, bitethe dog)  #不在词边界
16 >>> if m is not None:m.group()
17 ... 
18 the

1.2.10 用findall()找到每个出现的匹配部分

findall():用于非重叠的搜索某字符串中一个正则表达式模式出现的情况。返回的总是一个列表,如果没有匹配,返回空列表;如果成功找到匹配部分,则返回所有匹配部分的列表(按从左到右出现的顺序排列)。

1 >>> re.findall(car, car) 
2 [car]
3 >>> re.findall(car, scary) 
4 [car]
5 >>> re.findall(car, carry the barcardi to the car) 
6 [car, car, car]

1.2.11 用sub()(和subn())进行搜索和替换

两者几乎一样,都是将某字符串中所有匹配正则表达式模式的部分进行替换。用来替换的部分通常是一个字符串,但也可能是一个函数,该函数返回一个用来替换的字符串。

subn()还返回一个表示替换次数的数字,替换后的字符串和表示替换次数的数字作为一个元组的元素返回。

 1 >>> re.sub(X, Mr.Smith, attn: X\n\nDear X,\n) 
 2 attn: Mr.Smith\n\nDear Mr.Smith,\n
 3 >>> re.subn(X, Mr.Smith, attn: X\n\nDear X,\n) 
 4 (attn: Mr.Smith\n\nDear Mr.Smith,\n, 2)
 5 >>> print re.sub(X, Mr.Smith, attn: X\n\nDear X,\n) 
 6 attn: Mr.Smith
 7 
 8 Dear Mr.Smith,
 9 
10 >>> re.sub([ae], X, [abcdef]) 
11 [XbcdXf]
12 >>> re.subn([ae], X, [abcdef]) 
13 ([XbcdXf], 2)
14 >>> 

1.2.12 用split()分隔(分隔模式)

根据固定的字符串分隔。

1 >>> re.split(:, str1:str2:str3) 
2 [str1, str2, str3]

例子:Linux下who命令输出结果进行分隔

#!/usr/bin/env python

from os import popen
from re import split

f = popen(who, r)
for eachline in f.readlines():
    print split(\s\s+|\t, eachline.strip())
f.close()
输出结果:
[root@localhost tmp]# python rewho.py 
[grace, tty1, 2020-01-26 14:18 (:0)]
[grace, pts/0, 2020-01-26 14:18 (:0.0)]
[root, pts/1, 2020-01-26 14:19 (192.168.230.1)]

核心笔记:python原始字符串的用法

原生字符串的产生是由于正则表达式的存在,由于ASCLL字符和正则表达式特殊字符间产生的冲突。例如“\b”在ASCLL字符中代表退格符,但同时也是一个正则表达式的特殊字符,代表“匹配一个单词边界”。为了让RE编辑器把两个字符‘\b’当成想要表达的字符串,可以是用r’\b’。

 1 >>> m = re.match(\bblow, blow)
 2 >>> if m is not None:m.group()
 3 ... 
 4 >>> m = re.match(\\bblow, blow)
 5 >>> 
 6 >>> if m is not None:m.group()     
 7 ... 
 8 blow
 9 >>> m = re.match(r\bblow, blow) 
10 >>> if m is not None:m.group()     
11 ... 
12 blow

1.3 正则表达式示例

1.3.1 正则表达式示例

下面展示使用正则表达式处理字符串的不同办法。第一步:拿出一段代码用来生成随机数据,生成的数据用于以后操作。

 1 from random import randint, choice
 2 from string import lowercase
 3 from sys import maxint
 4 from time import ctime
 5 
 6 doms = [com, edu, net, org, gov]
 7 
 8 for i in range(randint(5, 10)):
 9     dtint = randint(0, maxint-1)
10     dtstr = ctime(dtint)
11     shorter = randint(4, 7)
12     em = ‘‘
13     for j in range(shorter):
14         em += choice(lowercase)
15 
16     longer = randint(shorter, 12)
17     dn = ‘‘
18     for j in range(longer):
19         dn += choice(lowercase)
20     
21     print %s::%s@%s.%s::%d-%d-%d % (dtstr, em, dn, choice(doms), dtint, shorter, longer)

接下来使用生成的字符串来进行测试:

测试1:提取时间戳中的有关星期的数据字段

 1 >>> data = Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
 2 >>> patt = ^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)
 3 >>> m = re.match(patt, data)
 4 >>> m.group()
 5 Fri
 6 >>> m.group(1)
 7 Fri
 8 >>> m.groups()
 9 (Fri,)
10 >>>

测试2:测试1例子的宽松表示

1 >>> data
2 Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
3 >>> patt = ^(\w{3})
4 >>> m = re.match(patt, data)
5 >>> m.group()
6 Fri
7 >>> m.group(1)
8 Fri
9 >>>

1.3.2 搜索与匹配的比较,“贪婪”匹配

例如我们要搜索三个连字符号(-)分隔的整型集。

 1 >>> data
 2 Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
 3 >>> patt = \d+-\d+-\d
 4 >>> re.search(patt, data).group()
 5 2072736638-5-6
 6 >>> patt = .+\d+-\d+-\d+
 7 >>> re.match(patt, data).group()
 8 Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
 9 >>> patt = .+(\d+-\d+-\d+)    
10 >>> re.match(patt, data).group()
11 Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
12 >>> re.match(patt, data).group(1)
13 8-5-6

出现上面的原因是:正则表达式本身默认是贪心匹配的。也就是说,如果正则表达式中使用到通配字,那它在按照从左到右的顺序求值时,会尽量“抓取”满足匹配的最长字符串。在上面的例子中,“.+”会从字符串的开始处抓取满足模式的最长字符,其中包含我们想得到的第一个整型字符起始到这个第一位数字“8”之间的所有字符。

一个解决办法是用“非贪婪”操作符“?”。这个操作符可以用在“*”、“+”或“?”的后面。它的作用是要求正则表达式引擎匹配的字符越少越好。

1 >>> patt = .+?(\d+-\d+-\d+)    
2 >>> re.match(patt, data).group(1)
3 2072736638-5-6
4 >>>

示例3:假设我们只想抽取三个整型字段里中间的那个整型部分

1 >>> data = Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6
2 >>> patt = -(\d+)-
3 >>> m = re.search(patt, data)
4 >>> m.group()
5 -5-
6 >>> m.group(1)
7 5
8 >>>



python-正则表达式

标签:dal   pil   error:   一个   并保存   创建   max   说明   特征   

原文地址:https://www.cnblogs.com/mrlayfolk/p/12235021.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!