一 简介:
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,
(在Python中)它内嵌在Python中,并通过 re 模块实现。
正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行
二 元字符与语法
元字符 | 说明 | 表达式示例 | 匹配后的字符串 |
. | 匹配任意除还行符' '外的字符。 | a.c | abc |
^ |
匹配字符串开头; 在多行模式中匹配每一行开头。 |
^abc | abc |
$ |
匹配字符串末尾; 在多行模式中匹配每一行末尾。 |
abc$ | abc |
* | 匹配前一个字符0或无限次。 | abc* |
ab abccc |
+ | 匹配前一个字符1或无限次。 | abc+ |
abc abcccc |
? | 匹配前一个字符0或1次。 | abc? |
ab abc |
{m} |
匹配前一个字符m次。 | ab{2}c | abbc |
{m,n} |
匹配前一个字符m至n次。 m和n可以省略:若省略m,则匹配0至n次; 若省略你,则匹配m至无限次。 |
ab{1,2}c |
abc abbc |
| |
|代表左右表达式任意匹配一个 它总是先尝试匹配左边表达式,一旦成功则跳过匹配右边的表达式 如果|没有被包括在()中,则它的范围是整个表达式。 |
abc|def |
abc def |
() |
被括起来的表达式将作为分组,从表达左边开始每遇到一个分组的左括号“(”,编号+1。 | (abc){2} | abcabc |
|
转义字符,使后一个字符改变原来的意思。 | a.c | a.c |
[] | 字符集。对应的位置可以是字符集中的任意字符。[a-c]就是给出范围 | a[bcd]e |
abe ace ade |
1 import re 2 # n = re.findall('alex.','afhsjalexdjas') #匹配任意除“ ”外的字符 3 # print(n) 4 #['alexd'] 5 6 # j = re.findall('a[.]cdr','wwwa.cdr') 7 # print(j) 8 #['a.cdr'] 9 10 # import re 11 # m = re.findall('alex$','adfalexdfsdhdhalex') #匹配字符串尾部 12 # print(m) 13 #['alex'] 14 15 # import re 16 # k = re.findall('^alex','alexdkjsalexkfksdjd') #匹配字符串开头的 17 # print(k) 18 #['alex'] 19 20 # h = re.findall('jorg*',"hgahajorgfzdjorgsf") #匹配钱一个字符0次或无线次 21 # print(h) 22 #['jorg', 'jorg'] 23 24 # g = re.findall('fork+','ajdiforkmfkfork. forkjd') #匹配前一个字符一次或无限次 25 # print(g) 26 #['fork', 'fork', 'fork'] 27 28 # f = re.findall('sds?','sds.jgk[sds]ktjsds') #匹配前一个字符0次或一次 29 # print(f) 30 #['sds', 'sds', 'sds'] 31 32 # d = re.findall('abc{2}c','abcccccabcccc') #匹配前一个字符n次 33 # print(d) 34 #['abccc', 'abccc'] 35 36 # import re 37 # f = re.findall('alex{3}','wwwalexxxx') 38 # print(f) 39 40 # s = re.findall('ab{1,2}c','abccabcccabccabcccc') #匹配前一个字符m至n次 41 # print(s) 42 #['abc', 'abc', 'abc', 'abc'] 43 44 # a = re.findall('assda|df','dasfsasfsdfdf') # |代表左右表达式任意匹配一个 45 # print(a) 46 #['df', 'df'] 47 48 # z = re.findall('(fg)','sfdsgsf9fgsdfgsgfg') #被括起来的表达式作为分组 49 # print(z) 50 #['fg', 'fg', 'fg'] 51 52 # x = re.findall(r'd','abf4h6f4ca7j5y3dga8j6bc') #转义字符,使后一个字符改变原来的意思 53 # print(x) 54 #['4', '6', '4', '7', '5', '3', '8', '6'] 55 56 # c = re.findall('[a-z]','abf4h6f4ca7j5y3dga8j6bc') #字符集。对应的位置可以是字符集的任意字符 57 # print(c) 58 #['a', 'b', 'f', 'h', 'f', 'c', 'a', 'j', 'y', 'd', 'g', 'a', 'j', 'b', 'c'] 59 60 # v= re.findall('[^1-9]','abf4h6f4ca7j5y3dga8j6bc') #取反。 61 # print(v) 62 #['a', 'b', 'f', 'h', 'f', 'c', 'a', 'j', 'y', 'd', 'g', 'a', 'j', 'b', 'c']
三 预定义字符集
:反斜杠后边跟元字符去除特殊功能
反斜杠后边跟普通字符实现特殊功能。
引用序号对应的字组所匹配的字符串
d | 匹配任何十进制数;它相当于类 [0-9] |
adc |
a1c |
D | 匹配任何非数字字符;它相当于类 [^0-9] | aDc | abc |
s | 匹配任何空白字符;它相当于类 [ fv] | asc | a c |
S | 匹配任何非空白字符;它相当于类 [^ fv] | aSc | abc |
w | 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_] | awc | abc |
W | 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_] | aWc | a c |
匹配一个单词边界,也就是指单词和空格间的位置 |
示例:
1 import re 2 m = re.findall('d','ww3wa8.d0') # d 匹配任何十进制数; 3 print(m) 4 5 import re 6 f = re.findall('D','ww3wa8.d0') #D 匹配任何非数字字符; 7 print(f) 8 9 import re 10 n = re.findall('s','ww3 wa8.d0') #s 匹配任何空白字符 11 print(n) 12 13 import re 14 y = re.findall('S','ww3 wa8.d0') #S 匹配任何非空白字符 15 print(y) 16 17 import re 18 k = re.findall('w','ww3 wa8.d0') #匹配任何字母数字字符 19 print(k) 20 21 import re 22 t = re.findall('W','ww3 wa8.d0') #W 匹配任何非字母数字字符 23 24 print(t) 25 26 运算结果: 27 ['3', '8', '0'] 28 29 ['w', 'w', 'w', 'a', '.', 'd'] 30 31 [' '] 32 33 ['w', 'w', '3', 'w', 'a', '8', '.', 'd', '0'] 34 35 ['w', 'w', '3', 'w', 'a', '8', 'd', '0'] 36 37 [' ', '.']
注释:例如:
'er/b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
只是匹配字符串开头结尾及空格回车等的位置, 不会匹配空格符本身
import re m = re.findall('abc','abc sdsadasabcasdsadasdabcasdsa') print(m) 输出结果: [] import re m = re.findall(r'abc','abc sdsadasabcasdsadasdabcasdsa') print(m) 输出结果: ['abc']
就是用在你匹配整个单词的时候。 如果不是整个单词就不匹配。 你想匹
配 I 的话,你知道,很多单词里都有I的,但我只想匹配I,就是“我”,这个时
候用 I
反斜杠的困扰
与大多数编程语言相同,正则表达式里使用""作为转义字符,这就可能造成反斜杠困扰。
假如你需要匹配文本中的字符"",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\":
前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\"表示。
同样,匹配一个数字的"\d"可以写成r"d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
示例:
import re m = re.findall('abc','abc sdsadasabcasdsadasdabcasdsa') print(m) 运算结果: [] import re m = re.findall(r'abc','abc sdsadasabcasdsadasdabcasdsa') print(m) 运算结果: ['abc']
贪婪匹配
*?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
从前面的描述可以看到'*','+'和'?'都是贪婪的,但这也许并不是我们说要的,
所以,可以在后面加个问号,将策略改为非贪婪,只匹配尽量少的RE
示例:
import re m = re.findall(r'a(d+?)','a23b') print(m) 输出结果: ['2'] import re i = re.findall(r'a(d+)','a23b') print(i) 输出结果: ['23']
re
模块
python通过re模块提供对正则表达式的支持。
1 例一: 2 import re 3 4 # 将正则表达式编译成Pattern对象 5 pattern = re.compile(r'hello') 6 7 # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None 8 match = pattern.match('hello world!') 9 10 if match: 11 # 使用Match获得分组信息 12 print match.group() 13 14 输出结果: 15 hello 16 17 18 例二: 19 import re 20 a = "123abc456" 21 i = re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #group(0) 列出整体 22 k = re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #group(1) 列出第一个括号匹配部分 23 h = re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #group(2) 列出第二个括号匹配部分 24 n = re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #group(3) 列出第三个括号匹配部分 25 print(i) 26 print(k) 27 print(h) 28 print(n) 29 运算结果: 30 123abc456 31 123 32 abc 33 456 34 35
1 import re 2 re.I #使匹配对大小写不敏感 3 re.L #做本地化识别(locale-aware)匹配 4 re.M #多行匹配,影响 ^ 和 $ 5 re.S #使 . 匹配包括换行在内的所有字符 6 print(re.findall(".","abc de")) 7 #输出 ['a', 'b', 'c', 'd', 'e'] 8 9 print(re.findall(".","abc de",re.S)) #匹配包括换行符在内的所有字符 10 #输出 ['a', 'b', 'c', ' ', 'd', 'e'] 11 re.U #根据Unicode字符集解析字符。这个标志影响 w, W, , B. 12 re.X #该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 13 14 re.S #将会匹配换行符,默认.逗号不会匹配换行符 15 print(re.findall(r"a(d+)b.+a(d+)b","a23b a34b")) 16 # 输出 [] 17 print(re.findall(r"a(d+)b.+a(d+)b","a23b a34b",re.S)) 18 #输出 [('23','34')] 19 20 re.M #^$ 标志将会匹配每一行,默认^只会匹配符合正则的第一行;默认$只会匹配符合正则的末行 21 print(re.findall(r"^a(d+)b","a23b a34b")) 22 #输出 ['23'] 23 print(re.findall(r"^a(d+)b","a23b a34b",re.M)) 24 #输出 ['23','34']
函数
1,compile()
编译正则表达式模式,返回一个对象的模式
pattern: 编译时用的表达式字符串
re.compile(pattern,flags=0)
flags 编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写,多行匹配等。
常用的flags有:
re.U | 根据Unicode字符集解析字符,这个标志影响w,W,,B |
re.S(DOTALL) | 使.匹配包括换行在内的所有字符 |
re.I(IGNORECASE | re.I(IGNORECASE |
re.L(LOCALE) | 做本地化识别(locale-aware)匹配,法语等 |
re.M(MULTILINE) | 多行匹配,影响^和$ |
re.X(VERBOSE) | 该标志通过给予更灵活的格式以便将正则表达式写得更易于理解 |
示例:
1 import re 2 tt = "Tina is a good girl, she is cool, clever, and so on..." 3 rr = re.compile(r'w*oow*') 4 print(rr.findall(tt)) #查找所有包含'oo'的单词 5 执行结果: 6 ['good', 'cool']
2,match
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个
match:re.match(pattern, string, flags=0)
Pattern对象是一个编译好的正则表达式
string: 匹配时使用的文本
flags: 编译时用的匹配模式。数字形式
示例:
import re m = re.match(r'hello', 'hello world!') print(m.group()) 输出结果: hello import re m = re.search('alex','alexdj') print(m.group()) 输出结果: alex
3,search
search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个
import re # 将正则表达式编译成Pattern对象 pattern = re.compile(r'you') # 使用search()查找匹配的子串,不存在能匹配的子串时将返回None # 这个例子中使用match()无法成功匹配 match = pattern.search('fork you!') if match: # 使用Match获得分组信息 print(match.group())
输出结果:
you
4,group和groups
findall(pattern, string, flags=0)
group() 返回被 RE 匹配的字符串 ;获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。
group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;
groups()不需要参数,返回一个元组,元组中的元就是正则表达式中定义的组。
示例:
1 import re 2 a = "374839dkjfkjrj85390" 3 print(re.search('([0-9]*)([a-z]*)([0-9]*)',a).group(0)) #group(0)返回re整体匹配的字符串 4 5 print(re.search('([0-9]*)([a-z]*)([0-9]*)',a).group(1)) #group(1)返回组号为1所匹配的字符串 6 7 print(re.search('([0-9]*)([a-z]*)([0-9]*)',a).group(2)) #group(2)返回组号为2所匹配的字符串 8 9 print(re.search('([0-9]*)([a-z]*)([0-9]*)',a).group(3)) #group(3)返回组号为3所匹配的字符串 10 11 print(re.search('([0-9]*)([a-z]*)([0-9]*)',a).groups(0)) #groups()不需要参数,返回一个元组,元组中的元就是正则表达式中定义的组 12 13 运算结果: 14 374839dkjfkjrj85390 15 374839 16 dkjfkjrj 17 85390 18 ('374839', 'dkjfkjrj', '85390')
start() 返回匹配开始的位置 ;group默认值为0
end() 返回匹配结束的位置;group默认值为0
span() 返回一个元组包含匹配 (开始,结束) 的位置;返回(start(group), end(group))
示例:
import re m = re.match(r'(w+) (w+)(?P<sign>.*)', 'hello world!') print ("m.group(1,2):", m.group(1, 2)) print ("m.groups():", m.groups()) print ("m.groupdict():", m.groupdict()) # print ("m.start(2):", m.start(2)) print ("m.end(2):", m.end(2)) print ("m.span(2):", m.span(2)) 输出结果: m.group(1,2): ('fork', 'you') m.groups(): ('fork', 'you', '!') m.groupdict(): {'sign': '!'} m.start(2): 5 m.end(2): 8 m.span(2): (5, 8)
5,split()
分割
split(pattern, string, maxsplit=0, flags=0)
根据指定匹配进行分组
示例:
import re p = re.compile(r'd+') print p.split('one1two2three3four4') 运算结果: ['one', 'two', 'three', 'four', '']
# #split 分割 import re origin = "hello alex bcd alex lge alex acd 19" n = re.split("aw+",origin) #全部分割 print(n) #输出['hello ', ' bcd ', ' lge ', ' ', ' 19'] m = re.split("aw+",origin,2) #分割几组 print(m) #输出['hello ', ' bcd ', ' lge alex acd 19'] c = re.split("a(w+)",origin,2) #先匹配括号里的 print(c) #输出['hello ', 'lex', ' bcd ', 'lex', ' lge alex acd 19']
4,findall
re.findall 以列表形式返回所有匹配的字符串
re.findall可以获取字符串中所有匹配的字符串。
示例:
# 返回全部能匹配的字符串
import re
p = re.compile(r'd+')
print(p.findall('one1two2three3four4'))
元算结果:
['1', '2', '3', '4']
6,finditer
返回一个顺序访问每一个匹配结果(Match对象)的迭代器
示例:
#返回一个顺序访问每一个匹配结果(Match对象)的迭代器 import re p = re.compile(r'd+') for m in p.finditer('one1two2three3four4'): print (m.group()) 运算结果: 1 2 3 4
7,sub
替换匹配的字符串
示例:
1 import re 2 origin = '1hdsjhsd234bj245njh226nj' 3 new_str,count = re.subn("d+","KKK",origin) 4 print(new_str) 5 #输出KKKhdsjhsdKKKbjKKKnjhKKKnj 6 7 8 9 import re 10 p = re.compile(r'(w+) (w+)') 11 s = "i say,hello world!" 12 print(p.sub(r'21',s)) #输出sayi,worldhello! 13 14 def func(m): 15 return m.group(1).title() + '' + m.group(2).title() 16 print(p.sub(func,s)) #输出ISay,HelloWorld!
8,subn
与 sub() 相同,但返回新的字符串和替换次数
示例:
import re p = re.compile(r'(w+) (w+)') s = 'i say, hello world!' print(p.subn(r'2 1', s)) def func(m): return m.group(1).title() + ' ' + m.group(2).title() print (p.subn(func, s)) 输出结果: ('say i, world hello!', 2) ('I Say, Hello World!', 2)
正则实例:
IP匹配
re.search(r"(([01]?d?d|2[0-4]d|25[0-5]).){3}([01]?d?d|2[0-4]d|25[0-5])","192.168.1.1")
电话:
^(?:+86)?(d{3})d{8}$ 这部分用于匹配移动电话
邮箱:
^[wd]+[dw\_.]+@([dw]+).([dw]+)(?:.[dw]+)?$
例:kongweiqi@live.com