目录
正则表达式
动机
- 文本处理已经成为计算机常见工作之一
- 对文本搜索,定位,提取的逻辑往往比较复杂
- 为了解决上述问题,产生正则表达式技术
定义:
- 正则表达式即文本的高级匹配模式,提供搜索,替代,获取等功能,本质是由一系列特殊符号和字符构成的子串,这个子串就是正则表达式。这个表达式描述了字符和字符的重复行为,可以匹配一类特征的字符串
特点:
- 方便进行检索和修改等文本操作
- 支持语言众多
- 灵活多样
目标:
- 熟练掌握所有正则表达式符号
- 能够编写简单的正则表达式,读懂较复杂的正则表达式
- 能够使用python re模块操作正则表达式
正则表达式匹配手段
- 通过设定有特殊意义的符号,描述符号和字符的重复行为及位置特征来表示一类特定规则的字符串
python ---> re模块 处理正则表达式
- re.findall(pattern,string)
功能:使用正则表达式匹配字符串
参数:
pattern 以字符串形式传入一个正则表达式
string 要匹配的目标字符串
返回值:返回一个列表,将目标子串中能用正则匹配的内容放入列表
正则表达式元字符
- 普通字符匹配(除了后续讲解的特殊字符全是普通字符)
- 元字符:a b c & #
- 匹配规则:匹配字符本身
In [41]:re.findall('abc',"abcdefgabcdab") In [42]:['abc', 'abc'] In [42]: re.findall('你好',"小平,你好,你好吗") Out[42]: ['你好', '你好']
- 或
- 元字符:|
- 匹配规则:匹配符号两侧的正则表达式均可
re.findall('ab|cd','abcdefgabasdfcd') ['ab', 'cd', 'ab', 'cd'] | 左右不要加没用的空格
- 匹配单个字符
- 元字符:. 代表所有单一字符,速配符
- 匹配规则:匹配除 \n 外任意一个字符
In [16]: re.findall('w.o','woo,wao is not wbo') Out[16]: ['woo', 'wao', 'wbo'] In [17]: re.findall('你.','你好,你坏 你是傻子 我不是') Out[17]: ['你好', '你坏', '你是']
- 匹配开始位置
- 元字符:^
- 匹配规则:匹配字符串的开头位置
In [3]: re.findall('^jame','jame,how are you') Out[3]: ['jame'] In [4]: re.findall('^jame','how are you,jame') Out[4]: []
- 匹配结束位置
- 元字符:$
- 匹配规则:匹配目标字符串的结束位置
In [5]: re.findall('py$','hello.py') Out[5]: ['py'] In [6]: re.findall('py$','hello.pyc') Out[6]: [] In [10]: re.findall('.+py$','hello.py') Out[10]: ['hello.py']
- 匹配重复
- 元字符:*
- 匹配规则:匹配前面出现的正则表达式0次或多次
fo* ---> f fo fooooooooooo 0次 1次 多次
In [11]: re.findall('ab*','absadasdasabbbbdsda') Out[11]: ['ab', 'a', 'a', 'a', 'abbbb', 'a']
- 匹配重复
- 元字符:+
- 匹配规则:匹配前面出现的正则表达式1次或多次
ab+ ---> ab abbbb
In [19]: re.findall('ab+','absadabdasabbbdsda') Out[19]: ['ab', 'ab', 'abbb']
- 匹配重复
- 元字符:?
- 匹配规则:匹配前面出现的正则表达式0次或1次
ab? --> a ab
In [20]: re.findall('ab?','abcea,adfgabbbb') Out[20]: ['ab', 'a', 'a', 'ab']
- 匹配重复
- 元字符:{n}
- 匹配规则:匹配前面的正则出现n次
ab{3} ---> abbb
In [28]: re.findall('ab{3}','abcea,adfgaaabbbbb') Out[28]: ['abbb']
- 匹配重复
- 元字符:{m,n}
- 匹配规则:匹配前面的正则m-n次
ab{3,5} --> abbb abbbb abbbbb
In [29]: re.findall('ab{3,6}','ab abbb abbbbabbbbb abbbbbb') Out[29]: ['abbb', 'abbbb', 'abbbbb', 'abbbbbb']
- 匹配字符集合
- 元字符:[字符集]
- 匹配规则:匹配字符集中任意一个字符
[abc123] ---> a b c 1 2 3
In [44]: re.findall('[aeiou]','hello world') Out[44]: ['e', 'o', 'o'] [0-9] [a-z] [A-Z] [0-9a-z] In [47]: re.findall('^[A-Z][a-z]*','Hello world') Out[47]: ['Hello']
- 匹配字符集
- 元字符:[^...]
- 匹配规则:匹配除了中括号中字符集的任意一个字符
In [48]: re.findall('[^0-9]+','hello2') Out[48]: ['hello'] In [49]: re.findall('[^l@#%]+','hello abc@123.com') Out[49]: ['he', 'o abc', '123.com']
- 匹配任意(非)数字字符
- 元字符:\d \D
- 匹配规则:
\d匹配任意一个数字字符 (类似于[0-9])
\D匹配任意一个非数字字符 (类似于[^0-9])In [52]: re.findall('\d{10}','13717776561') Out[52]: ['1371777656'] In [56]: re.findall('\D+','hello world') Out[56]: ['hello world']
- 匹配任意(非)普通字符(数字字母下划线,普通utf-8字符)
- 元字符:\w \W
- 匹配规则:
\w 匹配一个普通字符
\W 匹配一个非普通字符In [60]: re.findall('\w+','hello 河南信阳') Out[60]: ['hello', '河南信阳'] In [61]: re.findall('\W+','hello$河南%') Out[61]: ['$', '%']
- 匹配(非)空字符(空格,\r \n \t \v \f)
- 元字符:\s \S
- 匹配规则:
\s 匹配任意空字符
\S匹配任意非空字符In [114]: re.findall('\w+\s\w+','hello world') Out[114]: ['hello world'] In [116]: re.findall('\w+\s+\w+','hello \r\n\v\fworld') Out[116]: ['hello \r\n\x0b\x0cworld'] In [118]: re.findall('\S+','hi#%$ ash #$$()') Out[118]: ['hi#%$', 'ash', '#$$()']
- 匹配起止位置
- 元字符:\A \Z
- 匹配规则:
\A 匹配字符串开头位置 (相当于 ^)
\Z 匹配字符串结尾位置 (相当于 $)
In [81]: re.findall('\Ahi','hi,tom') Out[81]: ['hi'] In [82]: re.findall('\Ahi','this is tom') Out[82]: []
完全匹配:使用一个正则表达式可以匹配目标字符串的全部内容In [86]: re.findall('is\Z','this') Out[86]: ['is'] In [87]: re.findall('is\Z','this is tom') Out[87]: []
In [89]: re.findall('\A\w{5}\d{3}\Z','abcde12345') Out[89]: [] In [90]: re.findall('\A\w{5}\d{3}\Z','abcde123') Out[90]: ['abcde123'] 绝对匹配:使用开头和结尾位置的元字符将正则表达式放在其中, 则目标字符串仅有正则匹配内容时才能匹配上。
- 匹配(非)单词边界
(普通字符和非普通字符的交接位置认为是单词边界)- 元字符:\b \B
- 匹配规则:
\b 匹配单词边界位置
\B 匹配非单词边界位置In [110]: re.findall(r'\bis\b','the is test') Out[110]: ['is'] In [111]: re.findall(r'\Bis','the is test') Out[111]: [] In [112]: re.findall(r'\Bhe','the is test') Out[112]: ['he']
元字符总结:
- 匹配单个字符:a . [...] [^...] \d \D \w \W \s \S
- 匹配重复:* + ? {n} {m,n}
- 匹配位置:^ $ \A \Z \b \B
- 其他:| () \
正则表达式的转义
- 正则表达式特殊字符 . * ? $ ^ [] {} () \
- 在正则表达式如果想匹配这些特殊字符需要进行转义
In [229]: re.findall("\[\d+\]",'abc[123]') Out[229]: ['[123]']
- raw字符串--->原始字符串
特点:对字符串中的内容不进行转义,即表达原始含义
r"\b" ---> \b
"\\b" ---> \bIn [230]: re.findall("\\w+@\\w+\\.cn",'soze@tedu.cn') Out[230]: ['soze@tedu.cn'] In [231]: re.findall(r"\w+@\w+\.cn",'soze@tedu.cn') Out[231]: ['soze@tedu.cn']
贪婪与非贪婪
- 贪婪模式 : 正则表达式的重复匹配默认总是尽可能多的向后匹配内容
* + ? {m,n} - 非贪婪模式 : 尽可能少的匹配内容(相对贪婪)
*? +? ?? {m,n}?In [232]: re.findall(r"ab*?",'abbbbbbbbbb') Out[232]: ['a'] In [233]: re.findall(r"ab+?",'abbbbbbbbbb') Out[233]: ['ab']
正则表达式分组
- 使用()可以为正则表达式建立子组,子组不会影响正则表达式整体的匹配内容,可以被看做是一个内部单元
- 子组的作用:
- 形成内部整体,该表某些元字符的行为
In [154]: re.search(r'(ab)+',"ababababab").group() Out[154]: 'ababababab' In [159]: re.search(r'\w+@\w+\.(com|cn)',"lvze@tedu.cn").group() Out[159]: 'lvze@tedu.cn'
- 子组在某些操作中可以被单独提取出来
In [162]: re.search(r'\w+@\w+\.(com|cn)',"lvze@tedu.cn").group(1) Out[162]: 'cn' In [163]: re.search(r'(ab)+',"ababababab").group(1) Out[163]: 'ab'
- 子组的注意事项
- 一个正则表达式中可以有多个子组,区分第一,第二,,,子组
- 子组不要出现重叠的情况,尽量简单
捕获组和非捕获组(命名组,未命名组)
- 格式:(?P<name>pattern)
In [165]: re.search(r'(?P<dog>ab)+',"ababababab").group() Out[165]: 'ababababab' In [235]: re.search(r'(?P<dog>ab)',"ababababab").group() Out[235]: 'ab'
- 作用:
- 方便通过名字区分每个子组
- 捕获组可以重复调用
格式:(?P=name)
e.g.(?P<dog>ab)cd(?P=dog)===>abcdabIn [176]: re.search(r'(?P<dog>ab)cdef(?P=dog)','abcdefabcd').group() Out[176]: 'abcdefab'
正则表达式的匹配原则
- 正确性 ,能够正确匹配目标字符串
- 唯一性 ,除了匹配的目标内容,尽可能不会有不需要的内容
- 全面性 ,对目标字符串可能的情况要考虑全面不漏
In [173]: re.search(r'\d{17}(\d|x)','21803119950425135x').group() Out[173]: '21803119950425135x'
re模块的使用
- regex = re.compile(pattern,flags = 0)
- 功能:生成正则表达式对象
- 参数:
pattern 正则表达式
flags 功能标志位,丰富正则表达式的匹配 - 返回值:返回一个正则表达式对象
- re.findall(pattern,string,flags = 0)
- 功能:根据正则表达式匹配目标子串内容
- 参数:
pattern 正则表达式
string 目标字符串 - 返回值:列表,里面是匹配到的内容
如果正则表达式有子组,则只返回子组的内容import re pattern = r"([A-Z])(\S+)" #re调用 l = re.findall(pattern,'Hello World') print(l)#[('H', 'ello'), ('W', 'orld')]
- re.findall(string,pos,endpos)
- 功能:根据正则表达式匹配目标子串内容
- 参数
string 目标字符串
pos,endpos:截取目标字符串的起止位置进行匹配,默认是整个字符串 - 返回值:列表,里面是匹配到的内容
如果正则表达式有子组,则只返回子组的内容import re pattern = r"([A-Z])(\S+)" #compile对象调用 regex = re.compile(pattern) l = regex.findall("Hello World",3,20) print(l)#[('W', 'orld')]
- re.split(pattern,string,flags = 0)
- 功能:通过正则表达式切割目标字符串
- 参数:
pattern 正则
string 目标子串 - 返回值:以列表形式返回切割后的内容
import re l = re.split(r'\W','hi#asaf@对方%asdf') print(l)#['hi', 'asaf', '对方', 'asdf']
- re.sub(patter,replace,string,max,flags)
- 功能:替换正则表达式匹配内容
- 参数:
patter 正则
replace 要替换的内容
string 目标字符串
max 设定最多替换几处 - 返回值:替换后的字符串
import re s = re.sub(r'\s+','##',"This is a boy",2) print(s)#This##is##a boy
- re.subn(patter,replace,string,max,flags)
- 功能和参数同sub
- 返回值多了一个实际替换了几处
import re s = re.subn(r'\s+','##',"This is a boy",2) print(s)#('This##is##a boy', 2)
- re.finditer(pattern,string,flags)
- 功能:使用正则匹配目标子串
- 参数:
pattern 正则
string 目标子串 - 返回值:迭代对象---》迭代内容为match对象
import re obj = re.finditer(r"\d+",'2008年事情有点多,512地震,08奥运') #迭代出的内容是match对象 for i in obj: # print(dir(i)) print(i.group()) #2008 #512 #08
- re.fullmatch(patter,string,flags)
- 功能:完全匹配一个字符串
- 参数:
pattern 正则
string 目标子串 - 返回值:match对象,匹配到的内容
import re try: obj = re.fullmatch(r'\w+','abc123') print(obj.group()) except AttributeError as e: print(e)#abc123 #如果匹配的值不是\w+属性,则出错
- re.match(pattern,string,flags)
- 功能:匹配一个字符串起始内容
- 参数:
pattern 正则
string 目标子串 - 返回值:match对象,匹配到的内容
import re obj = re.match(r'foo','food on the table') print(obj.group())#foo
- re.search(pattern,string,flags)
- 功能:匹配第一个符合条件的字符串
- 参数:
pattern 正则
string 目标子串 - 返回值:match对象,匹配到的内容
import re obj = re.search(r'foo','Foo,food on the table,foo') print(obj.group())
regex对象的属性
- flags 标志为数值
In [205]: regex = re.compile(r'abcd') In [206]: regex.flags Out[206]: 32 In [223]: regex = re.compile(r'abc',re.I) In [224]: regex.flags Out[224]: 34
- pattern 正则表达式
In [214]: regex.pattern Out[214]: 'abc'
- groups 子组个数
In [215]: regex = re.compile(r'(ab)cd(ef)') In [216]: regex.groups Out[216]: 2
- groupindex 获取捕获组字典,键为组名值是第几组
In [217]: regex = re.compile(r'(?P<dog>ab)cd(?P<pig>ef)') In [218]: regex.groupindex Out[218]: mappingproxy({'pig': 2, 'dog': 1})
作业:
- 读取一个文本,
匹配文本中所有以大写字母开头的单词
匹配文本中所有数字
数字类型:234 -12 1.23 40% 1/2import re f = open("1.txt") l = [] #大写字母开头单词 pattern = r'\b[A-Z][\._0-9a-zA-Z]*' #数字 # pattern = r'-?\d+\.?/?\d*%?' for line in f: l += re.findall(pattern,line) print(l)
-
熟练元字符的使用规则
-
将finditer match search sub split 使用regex对象调用练习
-
复习tftp文件服务器项目(项目思路和项目代码)