python正则表达式

正则表达式(Regluar Expressions)又称规则表达式,在代码中常简写为REs,regexes或regexp(regex patterns)。它本质上是一个小巧的、高度专用的编程语言。 通过正则表达式可以对指定的文本实现匹配测试、内容查找、内容替换、字符串分割 等功能。

常用的正则表达式元字符,这里就不列举了
可以参考
http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
贪婪与非贪婪模式 这个文章写的不错直接下去看一下
https://blog.csdn.net/lxcnn/article/details/4756030
Python中的re模块提供了一个正则表达式引擎接口,它允许我们将正则表达式编译成模式对象,然后通过这些模式对象执行模式匹配搜索和字符串分割、子串替换等操作。re模块为这些操作分别提供了模块级别的函数以及相关类的封装。
Python中的re模块中最重要的两个类:

https://docs.python.org/3.6/library/re.html   官网文档
https://docs.python.org/3.6/howto/regex.html 官网文档
1.Regular Expression Objects     
正则表达式对象,用于执行正则表达式相关操作的实体
通过re模块 re.compile(pattern, flags=0) 编译生成
正则表达式对象中的方法和属性

参数说明:
string: 要匹配或处理的字符串
pos: 可选参数,表示从string字符串的哪个位置开始,相当于先对字符串做切片处理string[pos:]
endpos: 可选参数,表示到string字符串的哪个位置结束(不包含该位置)
maxsplit: regex.split()方法的可选参数,表示最大切割次数;默认值为0,表示能切割多少次就尽可能多的切割多少次
count: regex.sub()和regex.subn()方法的可选参数,表示最大替换次数;默认为0,表示能替换多少次就尽可能多的替换多少次
 repl: sub和subn函数中的repl表示replacement,用于指定将匹配到的子串替换成什么内容,需要说明的是该参数的值可以是一个字符串,也可以是一个函数
2.Match Objects     正则表达式匹配对象,用于存放正则表达式匹配的结果并提供用于获取相关匹配结果的方法
匹配对象中的方法和属性调用正则表达式对象的regex.match()、regex.fullmatch()和regex.search()得到的结果就是一个匹配对象

匹配对象支持以下方法和属性:

参数说明:
template: m.expand()方法中的template参数是一个模板字符串,这个字符串中可以使用分组对应的的数值索引进行后向引用(如:\1,\2)或命名后向引用(如\g<1>,\g<NAME>)来表示某个分组的占位符;m.expand()方法的执行过程实际上就是通过sub()方法把template字符串中的这些分组占位符用当前匹配对象中的数据进行替换。
default: m.groups()与m.groupdict()方法中的default都是为未匹配成功的捕获组提供默认匹配值的。
group: m.group()、m.start()、m.end()和m.span()方法中的group参数都表示要选择的分组索引值,1表示第一个分组,2表示第二个分组,依次类推,group参数的默认值是0,表示整个正则表达式所匹配的内容。
re模块提供的方法

说明: 通过对比会发现,上面这些re模块级别的函数除了re.compile、re.purge和re.escape这几个函数外,其它函数名都与正则表达式对象支持的方法同名。实际上re模块的这些函数都是对正则表达式对象相应方法的封装而已,功能是相同的。只是少了对pos和endpos参数的支持,但是我们可以手动通过字符串切片的方式来达到相应的需求,我们应该尽可能的使用模块级别的函数,这样可以增强代码的兼容性。

正则表达式的工作流程|:

1. 使用re模块进行正则匹配操作的步骤:
a  编写表示正则表达式规则的Python字符串str;
b 通过re.compile()函数编译该Python字符串获得一个正则表达式对象(Pattern Object)p;
c 通过正则表达式对象的p.match()或p.fullmatch()函数获取匹配结果--匹配对象(Match Object)m;
d 通过判断匹配对象m是否为空可知是否匹配成功,也可以通过匹配对象m提供的方法获取匹配内容。
2. 使用re模块进行内容查找、替换和字符串分隔操作的步骤
a 编写表示正则表达式规则的Python字符串str;
b 通过re.compile()函数编译该Python字符串获得一个正则表达式对象(Pattern Object)p;
c 通过正则表达式对象的p.search()或p.findall()或p.finditer()或p.sub()或p.subn()或p.split()函数完内容查找、替换和字符串分隔操作并获取相应的操作结果;
总结:
将一个表示正则表达式的Python字符串编译成一个正则表达式对象是使用正则表达式完成相应功能的首要步骤,re模块中用于完成正则表达式编译功能的函数为re.compile(pattern, flags=0)
 #使用正则表达式对象的match()fullmatch()方法
p = re.compile(r'[a-z]+$')
#match(string[, pos[, endpos]])
print(p.match('hello'))
print(p.fullmatch('hello'))
print(p.fullmatch('hello123'))
print(p.match('123hello'))
print(p.match('123hello',3)) #指定从哪个索引开始匹配
通过re提供的模块级别的函数来实现
#re.match(pattern, string, flags=0)
p.match(string[, pos[, endpos]])
re.match()re.fullmatch()中的pattern参数可以是正则表达式对象,也可以是Python正则表达式字符串
print(re.match(r'[a-z]+', 'hello').group())# 正则表达式字符串
print(re.match(p, 'hello123'))#正则表达式对象p
print(re.fullmatch(p, 'hello'))
print(re.match(p, 'hello1111'))
print(re.match(p, '123hello'[3:])) # 唯一不同的是这里

re.match()函数中的正则表达式参数加上边界元字符'^'和'$'就相当于re.fullmatch()了
当匹配过程是从字符串的第一个字符开始匹配时re.match(r'^[a-z]+$', 'hello123')与re.match(r'[a-z]+$', 'hello123')效果是一样的,
因为re.match()本来就是从字符串开头开始匹配的;
但是,如果匹配过程不是从字符串的第一个字符开始匹配时,比如指定索引值,它们是有区别的,具体请看下面这个例子。

print(re.match(r'^[a-z]+$', 'hello'))
print(re.fullmatch(r'[a-z]+$', 'hello'))
p1 = re.compile(r'[a-z]+$')
p2 = re.compile(r'^[a-z0-9]+$')
print(p1.match('123hello', 3))
print(p2.match('123hello',3))
运行的结果是:
<_sre.SRE_Match object; span=(3, 8), match='hello'>

None

match(string[, pos[, endpos]])
官网解释:
The optional second parameter pos gives an index in the string where the search is to start;
it defaults to 0. This is not completely equivalent to slicing the string;
the '^' pattern character matches at the real beginning of the string and at positions just after a newline,
but not necessarily at the index where the search is to start.。
大概的意思是当你指定^ 元字符的时候,我就不按你指定的索引开始匹配,我只匹配你实际字符串开始的位置
real beginning of the string就是说这个字符串实际的开始位置,多行模式下是匹配每一行的行首
string = '''A
B
X
''‘

print(re.search(r'^X', string))
print(re.search(r'^X', string, re.M)) #re.M 标志位下面会讲到

#re.match(r'[a-z]', string, flags=0)

 

标志位(flags):

它会影响正则表达式对象的匹配行为,但是有一点需要说明的是,只有当pattern参数是字符串时才能指定这个flags参数,否则会报错;如果pattren参数是一个正则表达式对象,则flags参数需要在调用re.compile()函数时指定。这些flag可以单独使用,也可以通过逻辑或操作符'|'进行拼接来联合使用。
re.I(IGNORECASE)忽略大小写,括号内是完整的写法
re.M(MULTILINE)多行模式,改变^和$的行为
re.S(DOTALL)点可以匹配任意字符,包括换行符
re.L(LOCALE)做本地化识别的匹配,不推荐使用
re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag
re.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白

正则表达式对象,则flags参数需要在调用re.compile()函数时指定。print(re.search(r'.', '\n'))
print(re.search(r'.', '\n', re.S))
string1 ="foo1\nfoo2\nfoo3"
string='''
foo1
foo2
foo3'''
print(re.search(r'foo.$', string).group())
print(re.findall(r'foo.$', string,re.M))
print(re.search(r'foo.$', string1, re.M))
这些flag可以单独使用,也可以通过逻辑或操作符'|'进行拼接来联合使用
print(re.search('D#test', 'doudou',flags=re.X|re.I))
print(re.search('.  #匹配所有字符串', 'doudou', re.X))

re模块的应用实例
1.匹配测试

     re.match(): 该函数是在字符串的开始位置进行匹配检测
     re.serach() 该函数会在字符串的任意位置进行匹配检测
     re.fullmatch: 匹配的是整个字符串

string = 'abcdef'
print(re.match(r'c', string))
print(re.search(r'c', string))
print(re.match(r'c', string))
print(re.search(r'^c', string))
print(re.search(r'^a', string))



2.内容查找
    re.serach() 该函数会在字符串的任意位置进行匹配检测    
    re.findall()返回的是所有匹配到的子串所组成的列表
    re.finditer()返回的是一个迭代器对象,该迭代器对象会将每一次匹配到的结果都作为一个匹配对象返回

  string='abababssss'
  print(re.findall(r's', string))
  aa = (re.finditer(r's', string))
  for i in aa:
      print(i)
      print(i.start(), i.end(), i.group())

3.内容替换

    re.sub():函数返回的是被替换后的字符串,如果字符串中没有与正则表达式相匹配的内容会返回原始字符串    
    re.subn():除了返回被替换后的字符串,还会返回一个替换次数,它们是以元组的形式返回的

#re.sub(pattern, repl, string, count=0, flags=0)#语法
text = 'pro----gram-files'
print(re.sub(r'-+', '', text))
print(re.sub(r'-+', '', text, count=1)) #connt=1表示替换一次
#re.subn(pattern, repl, string, count=0, flags=0)#语法
print(re.subn(r'-+', '', text)) #返回的是元组
运行结果:
programfiles
program-files
('programfiles', 2)

被替换的内容(repl参数)可以是一个字符串,还可以是一个函数名。
该函数会在每一次匹配时被调用,且该函数接收的唯一的参数是当次匹配相对应的匹配对象通过这个函数我们可以来做一些逻辑更加复杂的替换操作
比如我们想要得到'program files'这个结果

def funrepl(match_obj):
if match_obj.group() == '-':
return ' '
else:
return ''
text = 'pro----gram-files'
print(re.sub(r'-+', funrepl, text))
当被替换的内容(repl参数)是一个字符串时可以使用'\1'、'\g<NAME>'来引用正则表达式中的捕获组所匹配到的内容,
但是需要注意的是这个字符串必须带上r前缀,
r 原生态字符串,看下面实例
p1 = ".*\\\\s.*"
p2 = r".*\\s.*"
print(re.match(p, '\section').group())
print(re.match(p1, '\section').group())
p = r'def\s+([A-Za-z_]\w*)\s*\((?P<param>.*)\)'
repl = r'def py_\1(\g<param>)'
text = 'def myfunc(*args, **kwargs):'
print(re.sub(p, repl, text))

4.字符串分割
   re.split() 该函数会以匹配到的字符串当作分隔符最终返回被分割后的子串列表

 

#re.split(pattern,string,maxsplit=0,flags=0) 语法
print(re.split(r'[a-z]+', '0a3B9', maxsplit=0, flags=re.I))#maxsplit 指定分割的次数
如果用于作为分割符的正则表达式包含捕获组,那么该捕获组所匹配的内容也会作为一个结果元素被返回;
print(re.split(r'(\W+)', 'Words, words, words.'))
从Python3.5开始,如果作为分隔符的正则表达式可以匹配一个空字符串,将会引发一个warning;
print(re.split(r'x*', 'abcxde'))
从Python3.5开始,如果作为分隔符的正则表达式只能匹配一个空字符串,那么它将会被拒绝使用并抛出异常。
print(re.split(r'^$', '\nfoo\nbar\n', re.M))

re模块分组:

s = '140302200012291011'
ss = re.search('(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})', s)
print(ss.group())
print(ss.groups())
print(ss.group(1))
print(ss.group(city))
print(ss.groupdict())
p = re.compile(r'.*name\s+is\s+(\w+).*am\s+(?P<age>\d{1,3})\s+years.*tel\s+is\s+(?P<tel>\d{11}).*', re.DOTALL)
string = '''
My name is Tom,
I am 16 years old,
My tel is 13972773480.

'''
m = re.match(p, string)

m = p.match(string)
if m is None:
print('Regex match fail.')
else:
result = '''
name: %s
age: %s
tel: %s
'''
print(result % (m.group(1), m.group(2), m.group('tel')))


match.expand(template)方法可用于通过得到的匹配对象来构造并返回一个新的字符串,template是一个字符串,用于指定新字符串的格式;
从Python 3.5开始,未匹配到的分组将会替换为一个空字符串
if m is None:
print('Regex match fail.')
else:
template_str = '''
name: \g<1>
age: \g<2>
tel: \g<tel>
'''
print(m.expand(template_str))
 
 
 

 




转载于:https://www.cnblogs.com/centos-python/articles/9065644.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值