python基础-6 正则表达式
一 python正则简介
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。
正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
正则表达式并不是Python的一部分。正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强大。得益于这一点,在提供了正则表达式的语言里,正则表达式的语法都是一样的,区别只在于不同的编程语言实现支持的语法数量不同;但不用担心,不被支持的语法通常是不常用的部分。如果已经在其他语言里使用过正则表达式,只需要简单看一看就可以上手了。
下图展示了使用正则表达式进行匹配的流程:
正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。如果表达式中有量词或边界,这个过程会稍微有一些不同,但也是很好理解的,看下图中的示例以及自己多使用几次就能明白。
二 python正则的字符
1 普通字符
大多数字符和字母都会和自身匹配
1 >>> re.findall('alex','yuanaleSxalexwupeiqi') 2 ['alex']
2 元字符
元字符:. ^ $ * + ? { } [ ] | ( ) \
1 正则表达式: 2 字符匹配: 元字符 [] 3 . :任意单个字符 4 []:指定范围内的的任意单个字符 5 [0-9] 6 [a-z] 7 [A-Z] 8 [^]:指定范围内的任意单个字符 9 字符次数 匹配: 用来指定匹配其前面字符的次数 10 * : 任意次数 0次 1次或多次 11 例子:x*y x出现了y次 xxy xy y。 12 .*:匹配任意长度的字符 13 ?: 0次或1次 14 x\?y xy y xxy 15 贪婪模式:尽可能长的去匹配字符 16 17 + 1次或多次 18 {m}:,匹配m次 19 {m,n}:m次到n次 20 {m,}:至少m次 21 {0,n}:至多n次 22 位置锚定: 用于指定字符出现的位置 23 ^ :用于锚定行首 24 ^Char 以Char开头 25 $ :锚定行尾 26 char$ 以char结尾 27 ^$:空白行 28 29 \b : 锚定词首 \bchar 30 : 锚定词尾, char\b 31 例如: \bhello\b 匹配hello单词 32 分组: 33 元字符( ) 34 ab*xy 0个或者多个b 35 \(ab\)*xy 0个或者多个ab 36 引用: 37 38 \1: 后向引用,引用前面的第一个左括号以及与之对应的左括号中的模式所匹配到的内容 39 \2 40 ..... 41 (a.b)(c.d\)xy\1\2 : 必须再次出现前面括号分组的内容实体1次 后面的引用内容不再是正则 42 43 a3bc2dxya3bc2d 44 元字符 \ : 45 ?1234567\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_]\b: 匹配一个单词边界,也就是指单词和空格间的位置。
2.1 python 元字符 []说明
我们首先考察的元字符是"[" 和 "]"。
它们常用来指定一个字符类别,所谓字符类别就是你想匹配的一个字符集。输出所有符合的字符,单个单个的字符
字符可以单个列出,也可以用“-”号分隔的两个给定字符来表示一个字符区间。
例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。如果你只想匹配小写字母,那么 RE 应写成 [a-z].
元字符在字符集并不起作用。 元字符在中括号[]内就代表字符
1 re.findall("[abc]","yuanaleSxalexwupeiqi") 2 ['a', 'a', 'a'] 3 re.findall("[a-c]","yuanaleSxalexwupeiqi") 4 ['a', 'a', 'a'] 5 re.findall("[a-q]","yuanaleSxalexwupeiqi") 6 ['a', 'n', 'a', 'l', 'e', 'a', 'l', 'e', 'p', 'e', 'i', 'q', 'i'] 7 re.findall("[(an)]","yuanaleSxalexwupeiqi") 8 ['a', 'n', 'a', 'a'] 9 re.findall("[an]","yuanaleSxalexwupeiqi") 10 ['a', 'n', 'a', 'a']
1 >>> a = "123 ..*#$% ABC abc" 2 3 >>> re.findall("[..*]",a) 4 ['.', '.', '*']
[]:元字符[]表示字符类,在一个字符类[]中,只有字符^、-、]和\有特殊含义。
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
例如,[akm$]将匹配字符"a", "k", "m", 或 "$" 中的任意一个;"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。
测试
1 >>> re.findall("[akm$]","a$kcc3") 2 <strong>['a', '$', 'k'] 3 </strong>
2.2 python元字符 ()说明 结合引用:
括号内的为一个整体,分组。
1 re.findall("a\d+","a234b") 2 ['a234'] 3 re.findall("a(\d+)","a234b") 4 ['234'] 5 re.findall("a\d{1,2}","a234b") 6 ['a23'] 7 re.findall("a(\w+)","aaabbc4b") 8 ['aabbc4b'] 9 re.findall("ab(\d+)","aaabbc4b") 10 [] 11 re.findall("ab(\w+)","aaabbc4b") 12 ['bc4b'] 13 14 #括号前面是限定条件,只查找括号里面的,findall取的是组里面的内容,优先捕获。加上?:去掉
re.findall(r"a(\d+?)","a234b")
'a234'
测试
1 >>> p = re.compile('(a(b)c)d') 2 >>> m = p.match('abcd') 3 >>> m.group(0) 4 'abcd' 5 >>> m.group(1) 6 'abc' 7 >>> m.group(2) 8 'b'
1 <strong>比如vim正则该love 为Love</strong><br> he love her love l大写 he Love her love 2 <span style="background-color: #ffff00;">:1,20s@\(l\(..e\)\)\(.*\1\)@L\2\3@g</span> 3 \1: 后向引用,引用前面的第一个左括号以及与之对应的左括号中的模式所匹配到的内容 \1 = 前面括号内容,前面内容是什么\1就是什么 上面即 \1 =l \2 =ove
标签引用分组
(?P<sign>\d+)(?P=sign) == (\d+)\1
?P<sign>作为分组名 . 任意字符 \d 数字 ?P=sign 引用
1 >>> re.match(r'(\w+) (\w+)(?P<sign>.)\d(?P=sign)', 'hello world!3!').group() 2 'hello world!3!'
2.3 python + * ? {} 说明
- + 匹配+号前内容1次至无限次
- ? 匹配?号前内容0次到1次
- {m} 匹配前面的内容m次
- {m,n} 匹配前面的内容m到n次
- *?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
贪婪模式和非贪婪模式区别:
从前面的描述可以看到'*','+'和'?'都是贪婪的,但这也许并不是我们说要的,所以,可以在后面加个问号,将策略改为非贪婪,只匹配尽量少的RE。示例,
1 体会两者的区别: <strong>findall 只匹配输出 分组内容如果是分组的话,如果不是分组的话都输出匹配到输出的内容</strong> 后面介绍 2 >>> re.findall(r"a(\d+?)","a234b") # 非贪婪模式 如果\d+匹配的是两个数字的话, 3 ['2'] 4 >>> re.findall(r"a(\d+)","a234b") 5 ['234']
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"
1 >>> re.search('<(.*)>', '<H1>title</H1>').group() 2 '<H1>title</H1>' 3 re.search('<(.*?)>', '<H1>title</H1>').group() 4 '<H1>'
#如果前后均有限定条件,则非贪婪模式失效
1 注意比较这种情况: 2 >>> re.findall(r"a(\d+)b","a23b") 3 ['23'] 4 >>> re.findall(r"a(\d+?)b","a23b") #如果前后均有限定条件,则非匹配模式失效,不按照非贪婪模式 5 ['23']
2.4 python元字符 \ 说明
\:
- 反斜杠后边跟元字符去除特殊功能,字符转义
-
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\.
例如:deerchao\.net匹配deerchao.net,C:\\Windows匹配C:\Windows。
-
- 反斜杠后边跟普通字符实现特殊功能。
- 引用序号对应的字组所匹配的字符串
1 \d 匹配任何十进制数;它相当于类 [0-9]。
2 \D 匹配任何非数字字符;它相当于类 [^0-9]。
3 \s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
4 \S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
5 \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
6 \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
7 \b: 匹配一个单词边界,也就是指单词和空格间的位置。
1 >>> a = "123 ..*#$% ABC abc"<br>>>> re.findall("\d",a) 2 ['1', '2', '3'] 3 >>> re.findall("\s",a) 4 [' ', ' ', ' '] 5 >>> re.findall("\w",a) 6 ['1', '2', '3', 'A', 'B', 'C', 'a', 'b', 'c'] 7 >>> re.findall("\D",a) 8 [' ', '.', '.', '*', '#', '$', '%', ' ', 'A', 'B', 'C', ' ', 'a', 'b', 'c'] 9 >>> re.findall("\S",a) 10 ['1', '2', '3', '.', '.', '*', '#', '$', '%', 'A', 'B', 'C', 'a', 'b', 'c'] 11 >>> re.findall("\W",a) 12 [' ', '.', '.', '*', '#', '$', '%', ' ', ' '] 13 >>>
例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\b只是匹配字符串开头结尾及空格回车等的位置, 不会匹配空格符本身
例如 "abc sdsadasabcasdsadasdabcasdsa",
\sabc\s不能匹配,\babc\b可以匹配到"abc"
带\ 转义符 需要用r 忽略python的制表符查找
1 >>> re.findall("\babc\b","abc sdsadasabcasdsadasdabcasdsa") #这里匹配不到是因为没加r的原因,后面说明 2 [] 3 >>> re.findall(r"\babc\b","abc sdsadasabcasdsadasdabcasdsa") 4 ['abc']
1 \b 就是用在你匹配整个单词的时候。 如果不是整个单词就不匹配。 你想匹配 I 的话,你知道,很多单词里都有I的,但我只想匹配I,就是“我”,这个时候用 \bI\b 2 3 最后讲r作用
1 >>> re.findall(r"\bI","I love u") 2 ['I']
>>> re.findall(r"\bIl","Ilove u")
['Il']
2.5反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
例子:\S+匹配不包含空白符的字符串。
<a[^>]+>匹配用尖括号括起来的以a开头的字符串。
2.6分支条件
不幸的是,刚才那个表达式也能匹配010)12345678或(022-87654321这样的“不正确”的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
三 正则re模块的各种方法
1、match(pattern, string, flags=0)
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个。没有匹配,返回值为None
- 正则表达式 patter
- 要匹配的字符串 string
- 标志位,用于控制正则表达式的匹配方式 flags
代码
1 import re 2 3 obj = re.match('\d+', '123uuasf')#是一个对象,需要用group()方法提交返回值 4 if obj: 5 print obj.group()
开头没有数字,因此返回None
标志位
re.M 会匹配每一行,处理文件可以
1 re.I 使匹配对大小写不敏感 2 re.L 做本地化识别(locale-aware)匹配 3 re.M 多行匹配,影响 ^ 和 $ 4 re.S 使 . 匹配包括换行在内的所有字符 5 re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. 6 re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
标志位测试
re.S re.M
1 re.I 使匹配对大小写不敏感 2 re.L 做本地化识别(locale-aware)匹配 3 re.M 多行匹配,影响 ^ 和 $ 4 re.S 使 . 匹配包括换行在内的所有字符 5 >>> re.findall(".","abc\nde") 6 >>> re.findall(".","abc\nde",re.S) 7 re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. 8 re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 9 10 re.S:.将会匹配换行符,默认.逗号不会匹配换行符 11 >>> re.findall(r"a(\d+)b.+a(\d+)b","a23b\na34b") 12 [] 13 >>> re.findall(r"a(\d+)b.+a(\d+)b","a23b\na34b",re.S) 14 [('23','34')] 15 >>> 16 re.M:^$标志将会匹配每一行,默认^只会匹配符合正则的第一行;默认$只会匹配符合正则的末行 17 >>> re.findall(r"^a(\d+)b","a23b\na34b") 18 ['23'] 19 >>> re.findall(r"^a(\d+)b","a23b\na34b",re.M) 20 ['23','34'] 21 但是,如果没有^标志, 22 >>> re.findall(r"a(\d+)b","a23b\na34b") 23 ['23','43'] 24 可见,是无需re.M
1 re.x # X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。以下两个正则表达式是等价的: 2 a = re.compile(r"""\d + # the integral part 3 \. # the decimal point 4 \d * # some fractional digits""", re.X) 5 b = re.compile(r"\d+\.\d*")
测试
1 match 只从开头匹配 匹配到就输出=== 字符串 2 obj = re.match('\d+', '123uuasf') 3 print(obj.group()) 4 if obj: 5 print(obj.group()) 6 obj = re.match('\d+', '123uuasf') 7 输出C:\Python35\python3.exe E:/py_test/s8/s4.py123123
1 match 如果开头没匹配到或者 规则根本就都不匹配所有符合的 直接返回None,调用grou()方法就报错 2 obj = re.match('\d+', 'sdfuuasf') 3 print(obj.group()) 4 if obj: 5 print(obj.group()) 6 7 报错如下 8 C:\Python35\python3.exe E:/py_test/s8/s4.py 9 Traceback (most recent call last): 10 File "E:/py_test/s8/s4.py", line 8, in <module> 11 print(obj.group()) 12 AttributeError: 'NoneType' object has no attribute 'group'
标志位练习
1 ============================ 2 import re 3 a = 'a23b' 4 print re.findall('a(\d+?)',a) #['2'],\d+,重复一次以上。加上?只取最小次数,1次。findall查找括号中的字符组 5 print re.findall('a(\d+)',a) #['23'],\d+重复一次以上。 6 print re.findall(r'a(\d+)b',a) #['23'] 7 print re.findall(r'a(\d+?)b',a) # ['23'],前后均有限定条件,因此非匹配模式失效,不按照贪婪模式查找
8 ============================
9 b='a23b\na34b'
10 ''' . 匹配非换行符的任意一个字符'''
11
12 re.findall(r'a(\d+)b.+a(\d+)b',b) #[],没有将换行符去掉。b中有个\n.
13
14 re.findall(r'a(\d+)b',b,re.M) # ['23', '34']
15
16 re.findall(r'^a(\d+)b',b,re.M) # ['23', '34']
17
18 re.findall(r'a(\d+)b',b) #['23','34'] 可以匹配多行
19
20 re.findall(r'^a(\d+)b',b) # ['23'] 默认^只会匹配符合正则的第一行
21
22 re.findall(r'a(\d+)b$',b) # ['34'] 默认$只会匹配符合正则的末行
23
24 re.findall(r'a(\d+)b',b,re.M) #['23', '34']
25
26 re.findall(r'a(\d+)b.?',b,re.M) # ['23', '34']
27
28 re.findall(r"a(\d+)b", "a23b\na34b") # ['23', '34']
29 ---------------------------------------------------------------
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。
属性:
- string: 匹配时使用的文本。
- re: 匹配时使用的Pattern对象。
- pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
- endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
- lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
- lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:
- group([group1, …]):
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。 - groups([default]):
以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。 - groupdict([default]):
返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。 - start([group]):
返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。 - end([group]):
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。 - span([group]):
返回(start(group), end(group))。 - expand(template):
将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
#!/usr/bin/env python # _*_ coding:utf-8 _*_ __author__ = 'liujianzuo' import re m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello world!') print(r"m.string:", m.string) print(r"m.re:", m.re) print(r"m.pos:", m.pos) print(r"m.endpos:", m.endpos) print(r"m.lastindex:", m.lastindex) print(r"m.lastgroup:", m.lastgroup) print(r"m.group(1,2):", m.group(1, 2)) print(r"m.groups():", m.groups()) print(r"m.groupdict():", m.groupdict()) print(r"m.start(2):", m.start(2)) print(r"m.end(2):", m.end(2)) print(r"m.span(2):", m.span(2)) print(r"m.expand(r'\2 \1\3'):", m.expand(r'\2 \1\3'))
1 C:\Python35\python3.exe E:/py_test/s7/re_match.py 2 m.string: hello world! 3 m.re: re.compile('(\\w+) (\\w+)(?P<sign>.*)') 4 m.pos: 0 5 m.endpos: 12 6 m.lastindex: 3 7 m.lastgroup: sign 8 m.group(1,2): ('hello', 'world') 9 m.groups(): ('hello', 'world', '!') 10 m.groupdict(): {'sign': '!'} 11 m.start(2): 6 12 m.end(2): 11 13 m.span(2): (6, 11) 14 m.expand(r'\2 \1\3'): world hello!
2 search(pattern, string, flags=0)
根据模型去字符串中匹配指定内容,匹配单个,只匹配一次,匹配第一个,可以结合split 将匹配到内容分割 拼接 然后再次循环查找。因为findall尽管可以找到所有,但是在处理分组()时候分组外的内容匹配不到。而findall是返回列表 后面会有介绍
代码
1 import re 2 3 obj = re.search('\d+', 'u123uu888asf') 4 if obj: 5 print obj.group()
标志位同上解释
search练习,和match类似,返回值是一个对象或None,
1 search 如果匹配到一个就退出了。 2 import re 3 4 obj = re.search('\d+', 'u123uu888asf') 5 if obj: 6 print(obj.group()) 7 C:\Python35\python3.exe E:/py_test/s8/s4.py 8 123 9 10 search 如果匹配不到 group() 会报错 11 12 import re 13 obj = re.search('\d+', 'sdfuuasf') 14 15 print(obj.group()) 16 if obj: 17 print(obj.group()) 18 19 C:\Python35\python3.exe E:/py_test/s8/s4.py 20 Traceback (most recent call last): 21 File "E:/py_test/s8/s4.py", line 18, in <module> 22 print(obj.group()) 23 AttributeError: 'NoneType' object has no attribute 'group'
3、group和groups
group(0) 显示全部
group(1) 显示第一个分组()
group(2) 显示第二个分组()
如果没有分组或超出分组个数就会报错
1 a = "123abc456" 2 print re.search("([0-9]*)([a-z]*)([0-9]*)", a).group() 3 4 print re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(0) # 5 print re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(1) 6 print re.search("([0-9]*)([a-z]*)([0-9]*)", a).group(2) 7 8 print re.search("([0-9]*)([a-z]*)([0-9]*)", a).groups()
4 findall
以列表形式返回所有匹配的字符串
re.findall可以获取字符串中所有匹配的字符串。
搜索string,以列表形式返回全部能匹配的子串。
1 import re 2 3 p = re.compile(r'\d+') 4 print p.findall('one1two2three3four4') 5 6 ### output ### 7 # ['1', '2', '3', '4']
上述两中方式均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。
1 >>> re.findall(r'(asd)*','asdasd') 2 ['asd', ''] 3 # ['asd', ''] 匹配到了asdasd,但是只返回分组内的字符asd,(asd)*还可以表示'',匹配的话就可以匹配到一个'' 4 print(re.findall('a*','bb')) # ['', '', ''] 5 6 7 >>> re.findall(r'(asd)(asb)','asdasd') 8 [] 9 >>> re.findall(r'(asd)(asd)','asdasd') 10 [('asd', 'asd')] 11 第一个,两个组分别匹配到asd,作为一个元祖返回给列表 12 因为findall没有group的
findall
1 re.findall 以列表形式返回所有匹配的字符串 2 re.findall可以获取字符串中所有匹配的字符串。如: 3 4 p = re.compile(r'\d+') 5 print p.findall('one1two2three3four4') 6 7 8 re.findall(r'\w*oo\w*', text);获取字符串中,包含'oo'的所有单词。 9 10 import re 11 text = "JGood is a handsome boy,he is handsome and cool,clever,and so on ...." 12 print re.findall(r'\w*oo\w*',text) #结果:['JGood', 'cool'] 13 #print re.findall(r'(\w)*oo(\w)*',text) # ()表示子表达式 结果:[('G', 'd'), ('c', 'l')]
find 高级用法:?:
默认是取分组()内的信息,但是我想让分组外的匹配信息也取到,就要用到 ?:
1 >>> import re 2 >>> re.findall(r"www.(baidu|laonanhai).com","sdfsd www.baidu.comwww.laonanhai.com") 3 ['baidu', 'laonanhai'] 4 >>> re.findall(r"www.(?:baidu|laonanhai).com","sdfsd www.baidu.comwww.laonanhai.com") 5 ['www.baidu.com', 'www.laonanhai.com']
4.1 finditer() : 迭代查找
1 >>> p = re.compile(r'\d+') 2 >>> iterator = p.finditer('12 drumm44ers drumming, 11 ... 10 ...') 3 >>> for match in iterator: 4 ... match.group() , match.span() 5 ... 6 ('12', (0, 2)) 7 ('44', (8, 10)) 8 ('11', (24, 26)) 9 ('10', (31, 33))
5、sub(pattern, repl, string, count=0, flags=0)
用于替换匹配的字符串 pattern内必须为正则表达式,不能是正则表达式search或findall 查找到的赋值变量
比如我的计算器处理括号的方法,用正则search匹配到后,不能直接将变量出入 sub的pattern,因为不起作用
1 content = "123abc456" 2 new_content = re.sub('\d+', 'sb', content) 3 # new_content = re.sub('\d+', 'sb', content, 1) 4 print new_content
相比于str.replace功能更加强大
sub 疑点
sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):
使用repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用\id或\g<id>、\g<name>引用分组,但不能使用编号0。
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。
1 import re 2 3 p = re.compile(r'(\w+) (\w+)') 4 s = 'i say, hello world!' 5 6 print p.sub(r'\2 \1', s) 7 8 def func(m): 9 return m.group(1).title() + ' ' + m.group(2).title() 10 11 print p.sub(func, s) 12 13 ### output ### 14 # say i, world hello! 15 # I Say, Hello World!
subn方法 返回总共替换的次数
1 >>> re.subn(r'\d','ZZ','23*,5sfds.6hsdf') 2 ('ZZZZ*,ZZsfds.ZZhsdf', 4)
subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]):
返回 (sub(repl, string[, count]), 替换次数)。
1 import re 2 3 p = re.compile(r'(\w+) (\w+)') 4 s = 'i say, hello world!' 5 6 print p.subn(r'\2 \1', s) 7 8 def func(m): 9 return m.group(1).title() + ' ' + m.group(2).title() 10 11 print p.subn(func, s) 12 13 ### output ### 14 # ('say i, world hello!', 2) 15 # ('I Say, Hello World!', 2)
6、split(pattern, string, maxsplit=0, flags=0)
split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):
按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。
1 import re 2 3 p = re.compile(r'\d+') 4 print p.split('one1two2three3four4') 5 6 ### output ### 7 # ['one', 'two', 'three', 'four', '']
1 >>> content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" 2 >>> new_content = re.split('\*', content) 3 >>> # new_content = re.split('\*', content, 1) 4 ... print new_content 5 ["'1 - 2 ", ' ((60-30+1', '(9-2', '5/3+7/3', '99/4', '2998+10', '568/14))-(-4', '3)/(16-3', "2) )'"]
1 >>> content = "'1 - 2 * ((60-30+1*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2) )'" 2 >>> new_content = re.split('[\+\-\*\/]+', content) 3 >>> # new_content = re.split('\*', content, 1) 4 ... print new_content 5 ["'1 ", ' 2 ', ' ((60', '30', '1', '(9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14))', '(', '4', '3)', '(16', '3', "2) )'"]
split 分割有个缺点 中间内容切割后 作为分割符的内容如果很长,而且是用正则匹配的,可能只显示出部分 如下
1 >>> inpp = '1-2*((60-30 +(-40*7/8+6-5)*(9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3*323+3243/234)/ (16-3*2))' 2 >>> inpp=re.sub("\s*", '', inpp) 3 >>> re.search('\(([\+\-\*\/]*\d+\.*\d*){2,}\)', inpp).group() 4 '(-40*7/8+6-5)' 5 >>> re.split('\(([\+\-\*\/]*\d+\.*\d*){2,}\)', inpp, 1) 6 ['1-2*((60-30+', '-5', '*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3*323+3243/234)/(16-3*2))']
split无分组情况
1 origin = "hello alex bcd abcd lge acd 19" 2 n = re.split("a\w+",origin) 3 print(n) 4 5 6 C:\Python35\python3.exe E:/py/55/learn-python/oldboy/6/zhengze.py 7 ['hello ', ' bcd ', ' lge ', ' 19']
不包括a\w+,
split有分组情况
origin = "hello alex bcd abcd lge acd 19" n = re.split("(a\w+)",origin) print(n) C:\Python35\python3.exe E:/py/55/learn-python/oldboy/6/zhengze.py ['hello ', 'alex', ' bcd ', 'abcd', ' lge ', 'acd', ' 19']
7 re.compile(strPattern[, flag]): compile 编译方法
如果一个匹配规则,以后要使用多次,就可以先将其编译,以后就不用每次都在去写匹配规则
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为
Pattern对象。 第二个参数flag是匹配模式,取值可以使用按位或运算符'|'
表示同时生效,比如re.I | re.M
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则
表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式
对象的一个例子:
1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 regex = re.compile(r'\w*oo\w*') 4 print regex.findall(text) #查找所有包含'oo'的单词
四 、 正则中 原生字符引用 r
在代码中执行re模块之前,python会编译所有代码,所以python会有很多制表符,和re模块所认识的正则表达相冲突
python 中的制表符
1 转义字符 2 \(在行尾时) 续行符 3 4 \\ 反斜杠符号 5 \' 单引号 6 \" 双引号 7 \a 响铃 8 \b 退格(Backspace) 9 \e 转义 10 \000 空 11 \n 换行 12 \v 纵向制表符 13 \t 横向制表符 14 \r 回车 15 \f 换页 16 \oyy 八进制数yy代表的字符,例如:\o12代表换行 17 \xyy 十进制数yy代表的字符,例如:\x0a代表换行 18 \other 其它的字符以普通格式输出
总结:
由上可得之:在写python脚本如果要匹配\ 这个符合的话,需要怎么做呢? 规则:"\\\\"
首先python解释 编译代码时候,会先识别 到四个\ 会认为其是转义,故解释完后剩下两个\\
而后re正则识别到两个\的话,又是转义故此是一个\
1 >>> import re 2 >>> re.search("\\\\","fds\sdf").group() 3 '\\'
反斜杠的困扰
与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符"\",那么使用编程语言表示的正则表达式里将需要4个反斜杠"\\\\":前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
引入正题
如果遇到python内识别的制表符而不让其处理,而是交给re
我们可以用r来让python跳过,故只需转义一下让re处理后即可
1 >>> import re 2 3 >>> re.search(r"\\","fds\sdf").group() 4 '\\'
*****关于原生字符rawstring以及\: 说明
\n是换行,ASCLL码是10
\r是回车,ASCLL码是13
1 re.findall("\","abc\de") 2 3 f=open("C:\abc.txt")
\a是 转义字符 007,响铃符 BEL。
1 f=open(r"D:\abc.txt") 2 3 ??? 4 >>> re.findall(r"\d","ww2ee") 5 ['2'] 6 >>> re.findall("\d","ww2ee") 7 ['2']
>>强烈建议用raw字符串来表述正则
你可能已经看到前面关于原始字符串用法的一些例子了。原始字符串的产生正是由于有正则表达式的存在。原因是ASCII 字符和正则表达式特殊字符间所产生的冲突。比如,特殊符号“\b”在ASCII 字符中代表退格键,但同时“\b”也是一个正则表达式的特殊符号,代表“匹配一个单词边界”。
为了让RE 编译器把两个字符“\b”当成你想要表达的字符串,而不是一个退格键,你需要用另一个反斜线对它进行转义,即可以这样写:“\\b”。
但这样做会把问题复杂化,特别是当你的正则表达式字符串里有很多特殊字符时,就更容易令人困惑了。原始字符串就是被用于简化正则表达式的复杂程度。
事实上,很多Python 程序员在定义正则表达式时都只使用原始字符串。
下面的例子用来说明退格键“\b” 和正则表达式“\b”(包含或不包含原始字符串)之间的区别:
1 >>> m = re.match('\bblow', 'blow') # backspace, no match #退格键,没有匹配 2 3 >>> m = re.match('\\bblow', 'blow') # escaped \, now it works #用\转义后,现在匹 4 配了 5 6 >>> m = re.match(r'\bblow', 'blow') # use raw string instead #改用原始字符串
你可能注意到我们在正则表达式里使用“\d”,没用原始字符串,也没出现什么问题。那是因为ASCII 里没有对应的特殊字符,所以正则表达式编译器能够知道你指的是一个十进制数字
附带一张正则图片