正则表达式

一、正则基本知识

  正则在python中是以c实现的,在后续的爬虫等工作都需要使用到该模块,主要搜索文本的内容。搜索非常速度。

  http://tool.oschina.net/regex 

  https://www.regexpal.com/      两个个在线的正则表达式,可以用来借鉴

1.1 正则常用的匹配规则

  下面是列举出来一些常用的,更多的使用help(re)查看。

    正则默认都是贪婪匹配的(尽可能的多,贪吃)。还有一种懒惰匹配(取到最少那次就不干活了)。

    ?是一个非常有意思的规则。 自己单独的时候,表示0或1个字符。

       和贪婪的组合在一起的时候,就变成了控制贪婪变成懒惰匹配了。

.         代表任意字符,但是除了换行符
#
开头和结尾 ^ 代表字符串的开始 $ 代表字符串的结尾 ,如果是多行文本,默认只匹配第一行的结尾。 # 任意字符,贪婪匹配 * 匹配0或多次,贪婪匹配,取到满足的最多 + 匹配1或多次,贪婪匹配,取到满足的最多 ? 匹配0或次,贪婪匹配,取到满足的最多 ?还可结合*,+,?做懒惰匹配 # ?组合-懒惰匹配 *? +? ?? 前面的任意字符,得到最少的那次 # 指定次数 匹配 {m} 匹配m次。 {m,n} 匹配m到n次,和切片的使用方法一致。也是贪婪匹配 {m,} m到无穷 {n,} 0 到n次 a{m} 匹配6个a {m,n}? 更改成懒惰,得到最少的那次匹配 # 分组 () 下面会详细的讲解
# 字符集
  [] 只取其中一个
        [0-9]     代表 1到9,
        [a-z]     代表 a到z
        [a-zA-z0-9] 所有的字符和数字
        [abc]     匹配任意一个
        [^9]     除了9以外其他的所有
# 或
  |      常常搭配字符集和分组使用,[a|b]:找到a了,就不找b了,反之相同。

1.2 转义字符 \

   python的正则规则是以引号 包围的,里面的的一些字符 要代表本身的含义,或 转成其他意思,就需要这个\。

   红色的为常用的。

\.        默认.是代表任意字符,我们可以让他转义为。本身
\A       只在字符串开头进行匹配。
\b       匹配位于开头或者结尾的空字符串
\B       匹配不位于开头或者结尾的空字符串
\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_]
\Z       只在字符串结尾进行匹配
\number  在分组中使用,类似占位符

 

二 、两种使用方法

2.1 方法1:compile

  利用compile方法,生成一个re对象,好处是可以多次使用

import re
res = re.compile('\d{3}')            # 第一步,把正则字符串进行编码,返回一个re对象,保存为一个常量
result = res.search('I am hui 123')  # 第二步,把compile返回的对象,去匹配字符串,返回一个mactch对象
result.group()                       # 第三步,使用match对象的group方法,返回实际匹配的对象

    正则支持链式编程

2.2 方法2:re.方法

  直接使用re的方法,对于单一的使用比较方便,如果每次使用,每次都要定义。

import re
x = re.search('\d{3}', 'I am hui 123') # 直接使用match对象
x.group()                              # 使用match对象的group方法,返回实际匹配的对象

    正则支持链式编程

 

三、函数

3.1 compile

   compile(pattern, flags=0)

    Compile a regular expression pattern into a regular expression object re.compile(pattern, flags=0)

    把正则表达式的模式和标识转化成正则表达式对象,供 match() 和 search() 这两个 函数使用。

  常用的flags: 

re.I    忽略大小写
re.L    表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M    多行模式
re.S    把‘.’切换成 包含换行符,默认 点 是不包含换行符号的。
re.X    为了增加可读性,忽略空格和’ # ’后面的注释

  一个正则的注释的列子:

import re

regex = re.compile(r'(\d{1,3}\.){3}\d{1,3}')  # 错误写法
regex = re.compile(r'''
(2[0-4]\d|25[0-5]|[01]?\d\d?\.)  # 代表一组ip,包含后面的点
{3}                              # 表示3组
(2[0-4]\d|25[0-5]|[01]?\d\d?)    # 最后一组数字
''', re.X)
print(regex.match('192.168.1.1'))
print(regex.match('999.999.999.999'))  # 非正常的ip

 

 

3.2 seach 

  搜索整个字符串,返回第一个匹配的对象-match对象

  search(pattern, string, flags=0)
    Scan through string looking for a match to the pattern, returning
    a match object, or None if no match was found.

import re
s = """
1334-1234-113
133-1234-2123
135-4567-3456
de8ug@foxmail.com
lilei@qq.com
hmm.lee@goglr.com
https://github.com
https://taobcom.com
"""
target = '\d{4}'
target = '\d{3}(-\d{4}){2}'
regex = re.compile(target)
result = re.search(regex, s)
if result:
    print(result.group())
else:
    print('找不到')

 

3.2 match

  匹配字符串的开头,符合则返回一个match对象。

  注意match 和 seach的不同。两者都是只匹配一次,找到符合就返回,后面的就不再匹配。如果不符合就返回None

      macth:只匹配字符串的开头,注意前面的空白字符,特别是/n 换行。

      seach:搜索整个字符串。

import re
reg = re.compile('\d{3}')
s1 = '1234dasd'            # 正常内容
s2 = '/n1234dasd'         # 前面有换行符
s3 = ' 123'                    # 前面有空格
print(reg.match(s1))
print(reg.match(s2))
print(reg.match(s3))      

结果:
<_sre.SRE_Match object; span=(0, 3), match='123'>
None
None

 

3.3 findall

  匹配所有的字符串,到结束为之。返回一个列表。

import re
s = 'ferfewf234ed3de8ge4r3434rde8ger3r3rde8gede8ger34rf34r'

rege = re.compile('de8ge')
# rege = re.compile('de(8)ge')  # 进行分组
result = rege.findall(s)
print(result)

 

3.4 spilit

  使用正则的规则,来进行分割。类似字符串的spilt

import re

s = 'ferfewf234ed3de8ge4r3434rde8ger3r3rde8gede8ger34rf34r'
rege = re.compile('de8ge')    # 抛弃了de8ge
rege = re.compile('(de8ge)')  # 以de8ge进行分割,但是会返回de8ge
result = rege.split(s)
print(result)

 

3.5 sub 

  字符串中也有字符串的替换,replace,。正则中使用sub来替换字符串的内容,比起字符串的内容,整体更灵活。

第一种使用分组进行替换

import re
s = '字符串格式: 10/01/2008,  12/25/2018'
re_date = re.compile(r'(\d+)/(\d+)/(\d+)') # r是raw的意思,原生字符串
x=re_date.sub(r'\3-\1-\2', s)
print(x)

第二种 进行字符替换

import re
s = """
pytyhon is hard to learn,   坚持下,
没多少了        ok?
"""
# print(s)
regex = re.compile('\s+')
print(regex.sub('', s))

 

 

四、扩展知识

4.1 贪婪匹配 与 懒惰匹配

    ?是一个非常有意思的规则。

        1.  自己单独的时候,表示0或1个字符。

        2. 和贪婪的组合在一起的时候,就变成了控制贪婪变成懒惰匹配了。

*?             重复任意次,但尽可能少重复
+?             重复1次或更多次,但尽可能少重复
??             重复0次或1次,但尽可能少重复
{n,m}?         重复n到m次,但尽可能少重复
{n,}?          重复n次以上,但尽可能少重复
# 小案列,想匹配引号内部的,说话的内容
import re
text = 'Ipone say "yes." PC say "No."'
regex = re.compile('"(.*)"')    # 使用贪婪匹配,会得到最长的那串
#regex = re.compile('"(.*?)"') # 加上?,变成懒惰匹配就正常了   
print(regex.findall(text))

 

4.2 分组

  分组是用()来表示的,分组在我个人感觉 有三种作用:

    1.   将某些规律看成是一组,然后进行组级别的重复。

    2.   分组之后,可以通过后向引用简化表达式。

    3.   和find组合,查找指定的字符

第一个作用

  用ip地址(这个是简单版本,ip的真实看上面)作为实例:

    \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
但仔细观察,我们可以发现一定的规律,可以把.\d{1,3}看成一个整体,也就是把他们看成一组,再把这个组重复3次即可。表达式如下:
    \d{1,3}(\.\d{1,3}){3}
这样一看,就比较简洁了。

 

第二个作用:

  首先强调一个知识点,后向引用,赋值的是匹配后的结果,非正则表达式。

 <title>.*</title>

       可以看出,上边表达式中有两个title,完全一样,其实可以通过分组简写。表达式如下:

       <(title)>.*</\1>

       这个例子实际上就是反向引用的实际应用。对于分组而言,整个表达式永远算作第0组,在本例中,第0组是<(title)>.*</\1>,然后从左到右,依次为分组编号,因此,(title)是第1组。

       用\1这种语法,可以引用某组的文本内容,\1当然就是引用第1组的文本内容了,这样一来,就可以简化正则表达式,只写一次title,把它放在组里,然后在后边引用即可。

       以此为启发,我们可不可以简化刚刚的IP地址正则表达式呢?原来的表达式为\d{1,3}(.\d{1,3}){3},里边的\d{1,3}重复了两次,如果利用后向引用简化,表达式如下:

       (\d{1,3})(.\1){3}

       简单的解释下,把\d{1,3}放在一组里,表示为(\d{1,3}),它是第1组,(.\1)是第2组,在第2组里通过\1语法,后向引用了第1组的文本内容。

       经过实际测试,会发现这样写是错误的,为什么呢?

       小菜一直在强调,后向引用,引用的仅仅是文本内容,而不是正则表达式!

       也就是说,组中的内容一旦匹配成功,后向引用,引用的就是匹配成功后的内容,引用的是结果,而不是表达式。

       因此,(\d{1,3})(.\1){3}这个表达式实际上匹配的是四个数都相同的IP地址,比如:123.123.123.123。

 

第三作用:

  和find组合,提取组的内容。 先匹配整个正则表达式,根据结果再次提取()里面的内容

import re
data = '''
○ 4.1日,共有4人面试,手机号分别是13812345678,15112345678,13812345678,15112345678
○ 4.5日,共有6人面试13812345678,15112345678,13812345678,15112345678,13812345678,15112345678
○ 4.7日,共有3人面试13812345678,15112345678,13812345678
○ 4.8日,共有5人面试15112345678,13812345678,15112345678,13812345678,15112345678
4.30日,共有6人面试13812345678,15112345678,13812345678,15112345678,13812345678,15112345678
'''

regex = re.compile('共有(\d+)人')  # 先匹配整个正则表达式,根据结果再次提取()里面的内容
sum_people = sum([int(i) for i in regex.findall(data)])
print(sum_people)

 

分组命名:

  对于后向引用采用编号的方式进行替换,容易混淆,采用命名的方式便于识别

import re
# regex = re.compile(r'(\d+)\.(\d+)')                 # 使用编号替换,但是容易混淆,下面的方式采用命名
# print(regex.sub(r'\1月\2日', memo_text))

regex = re.compile(r'(?P<month>\d+)\.(?P<day>\d+)')
print(regex.sub(r'\g<month>月\g<day>日', memo_text))

 

 

    

五、 常用一些正则

import re

RE_PHONE = re.compile('\d{3}-\d{8}|\d{4}-\d{7}')


def phone(str1: str)-> list:
    "输入一个字符串,从中返回一个列表"
    return RE_PHONE.findall(str1)


def main():
    s = """
    010-23293293deuju010-23223293
    0111-3234123
    """
    print(phone(s))

if __name__ == '__main__':
    main()
匹配电话号码
匹配腾讯QQ号:  [1-9][0-9]{4,}  腾讯QQ号从10000开始 
只能输入汉字:  ^[\u4e00-\u9fa5]{1,8}$
只能输入由数字和26个英文字母组成的字符串:  “^[A-Za-z0-9]+$”
验证用户密码:  “^[a-zA-Z]\w{7,17}$”正确格式为:以字母开头, 长度在8-18之间, 只能包含字符、数字和下划线。

 

import re

# 验证电话
RE_PHONE = re.compile('\d{3}-\d{8}|\d{4}-\d{7}')
# 验证汉字
RE_CH = re.compile('^[\u4e00-\u9fa5]{1,8}$')
# 验证密码
RE_PWD = re.compile('^[a-zA-Z]\w{7,17}$')


def phone(text: str)-> list:
    "输入一个字符串,从中返回一个列表"
    return RE_PHONE.findall(text)


def verify(regex: '正则表达式', text: str)-> list:
    "验证用户名和密码"
    if regex.match(text):
        return True
    else:
        return False


def main():
    s = """
    010-23293293deuju010-23223293
    0111-3234123
    """
    # print(phone(s))
    print(verify(RE_CH, ''))
    print(verify(RE_PWD, 'dewu231_*'))
    

if __name__ == '__main__':
    main()
用函数来实现

 

   

 

    

 

    

转载于:https://www.cnblogs.com/louhui/p/8971497.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值