• 【python之路25】正则表达式


    一、正则表达式简介

    就其本质而言,正则表达式(或RE)是一种小型的、高度专业化的(在python中),它内嵌在python中,并通过RE模块实现。正则表达式编译成一系列字节码,然后由用C编写的匹配引擎执行。

    可以用正则表达式测试工具进行测试》

    二、字符匹配(普通字符、元字符)

    普通字符:大多数字符和字母都会和自身匹配

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('alex','faljfaljflajalexaa')
    print(li) #打印输出['alex']

    元字符的作用:

    .    ----代表除了换行符以外的其他任何字符

    ^   ----代表以后面的字符开始

    $   ----代表以前面的字符结束

    []  -----字符集,[a-z]代表小写字母从a到z的任何一个字母,[0-9]代表0-9的任何一个数字,[.]代表字符.,[a9]代表a或9,[^a-z]代表除了a-z的其他任何字符

       ------反斜杠后面跟元字符,去掉特殊功能变为普通字符;后面跟普通字符实现特殊功能;

    数字引用序号对应的字组所匹配的字符串,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.search(r'(alex)(eric)com2','alexericcomeric').group()
    print(li) #alexericcomeric,其中2代表的是第2组括号

    d 匹配任何十进制数字,相当于[0-9]

    D 匹配任何非数字字符,相当于[^0-9]

    回车符(
    )、换行符(
    )、水平制表符(	)、垂直制表符(v)、换页符(f)

    s 匹配任何空白字符,相当于[ fv]

    S 匹配任何非空白字符,相当于[^ fv]

    w 匹配任何字母数字字符,相当于[0-9a-zA-Z_]

    W 匹配任何非字母数字字符,相当于[^0-9a-zA-Z_]

     匹配一个单词和边界,也就是单词和空格间的位置,作用:就是你在匹配整个单词的时候,如果不是整个单词就不匹配I,很多单词里都有I的,这时候用I就表示匹配整个单词I,而不是单词中包含的I.

    例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall(r'[a-z]+','how are you')
    print(li) #是字母与空格之间的边界

    如下面例子,有张三和张三丰,想匹配张三就可以用边界匹配:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall(r'张三','张三 张三丰  李四 李四光 张三杰 张三')
    print(li) #打印输出:['张三', '张三'],如果没有那么匹配出4个张三

    |  表示或者,x|y表示匹配x或者y,例如:匹配IP地址

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    #匹配IP地址
    import re
    li = 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.12').group()
    print(li)

    元字符之量词:

    *   -----代表任意个字符,0-多个字符

    +  -----代表1-多个字符

    ?   ------代表0-1个字符

    {} ------代表重复固定次数,如:{3}重复3次,{3,}大于等于3次,{3,5}重复3-5次,{,3}重复0-3次

    三、贪婪模式与最少匹配模式(?)

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('alex*','ajalexxxxxaa')
    print(li) #打印输出['alexxxxx'],匹配多个字符时通常默认为贪婪模式

    数量元字符后面加上?可以变为最少匹配模式,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('alex*?','ajalexxxxxaa')
    print(li) #打印输出['ale'],*后面加上?,切换为最少匹配模式

    但当两边字符都能匹配上,中间加?,不会变为最少匹配模式

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('ad+?b','a23b')
    print(li) #打印输出['a23b']

     四、正则表达式re的函数

    1、match函数(只能匹配开始的字符,并且只匹配一次)

    用法:re.match(pattern,string,flags=0)  ----pattern正则表达式字符串,string,正则表达式作用于的字符串,flags编译标志位,用于修改正则表达式的匹配方式,例如大小写、多行匹配等。主要有以下选项:

    re.I    IGNORECASE忽略大小写,使匹配的大小写不敏感

    re.X   VERBOSE忽略空格,可以为方便观看而做注释用。

    re.M   MULTILINE多行匹配,影响^和$

    re.S   DOTALL使.匹配换行符在内的所有字符,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li1 = re.findall('.','abc
    de')  #['a', 'b', 'c', 'd', 'e'] 
    li2 = re.findall('.','abc
    de',re.S) #['a', 'b', 'c', '
    ', 'd', 'e']
    print(li1,li2)

    一旦匹配成功会返回一个match object对象,该对象的方法如下:

    group()  ---返回re匹配的字符串

    start()   ----返回匹配开始的位置

    end()   ------返回匹配结束的位置

    sapan()  -----返回匹配一个元组包含匹配(开始,结束)的位置

    group()  -----返回re整体匹配的字符串,可以一次输入多个组号

    groups()  -----返回一个元组,元组中包含所有分组结果

    groupdict()  -----返回一个字典,字典中包含所有的分组结果

    1)group() 返回re整体匹配的字符串,相当于group(0)

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group()
    print(li)  #打印输出123abc456

    2) group(n,m)  返回元组,组号为n,m所匹配的字符串,如果组号不存在,则抛出IndexError异常

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group(1,2)
    print(li)  #打印输出('123', 'abc')

    也可以group(n) 返回组号所匹配的字符,例如

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li0 = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group(0)  #123abc456
    li1 = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group(1)  #123
    li2 = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group(2)  #abc
    li3 = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').group(3)  #456
    print(li0,li1,li2,li3)

     3)groups() 返回元组,将所有组号匹配到的字符串以元组的形式返回,通常groups不需要参数。

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.search('([0-9]*)([a-z]*)([0-9]*)','123abc456').groups()
    print(li)  #打印输出('123', 'abc', '456')

    4)group,groups,groudict的用法及区别,如:下面三个例子:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    str = 'hello how are you!'
    r = re.match('hw+',str)
    print(r.group()) #打印输出:hello
    print(r.groups()) #打印输出:()
    print(r.groupdict()) #打印输出:{}
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    str = 'hello how are you!'
    r = re.match('(h)(w+)',str)
    print(r.group()) #打印输出:hello
    print(r.groups()) #打印输出:('h', 'ello')
    print(r.groupdict()) #打印输出:{}
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    str = 'hello how are you!'
    r = re.match('(?P<a1>h)(?P<a2>w+)',str)
    print(r.group()) #打印输出:hello
    print(r.groups()) #打印输出:('h', 'ello')
    print(r.groupdict()) #打印输出:{'a1': 'h', 'a2': 'ello'}

    2、search函数(浏览全部字符串,匹配第一个符合规则的字符串)

    参数与match完全相同

    3、findall函数(匹配所有符合的字符,匹配多次) finditer()函数

    findall,如果用到组,那么优先返回组内容,如果想返回所有内容,则需要在组前面加?:,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('www.(baidu|laonanhai).com','www.baidu.com')
    print(li)  #打印输出:['baidu']
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('www.(?:baidu|laonanhai).com','www.baidu.com')
    print(li)  #打印输出:['www.baidu.com']

    findall函数返回一个列表,finditer返回的是一个迭代器

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    iter_object = re.finditer('d','one1two2three3four4')
    print(iter_object)  #<callable_iterator object at 0x000001CF23FBA8D0>
    for i in iter_object:
        print(i.group(),i.span())
    #打印输出
        # 1(3, 4)
        # 2(7, 8)
        # 3(13, 14)
        # 4(18, 19)

    分组如果是量词为*则可以匹配到空字符,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    n = re.findall('(dasd)*','lasd2asdp3asd98kif')
    print(n) #['', '', '', '', '2asd', '', '3asd', '', '', '', '', '', '']
    import re
    n = re.findall('(dasd)+','lasd2asdp3asd98kif')  #如果能多次匹配则显示最后一次匹配,lasd2asd匹配到的是2asd
    print(n) #['2asd', '3asd']

    分组括号内部加":?"可以取消分组,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    n = re.findall('(?:dasd)+','1asd2asdp3asd98kif')  #分组内部加?:可以取消分组效果
    print(n) #['1asd2asd', '3asd']

    4、sub与subn函数

    re.sub(pattern,repl,string,max=0)

    参数:pattern正则表达式字符串,repl替换为的字符串,string要查找替换的字符窜,max=0 全部替换,1从左到右替换1个,2从左到右替换两个.......

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.sub('g.t','have','I get A,I got B,I gut C')
    print(li)  #打印输出 have A,I have B,I have C

     subn函数返回一个元组,元组中包含两个元素,第1个元素是替换后的字符串,第2个元素为替换次数,例如:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.subn('g.t','have','I get A,I got B,I gut C')
    print(li)  #打印输出 ('I have A,I have B,I have C', 3)

     5、compile函数

    re.compile(strPattern[,flag])

    这个方法是pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象,第2个参数为编译标志位,可以利用,re.I等。

    把常用的正则表达式编译为Pattern对象,可以被反复调用,从而提高效率。

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    text = 'JGood is a hansome boy,he is cool,clever.'
    regex = re.compile(r'w*oow*')
    print(regex.findall(text)) #打印输出['JGood', 'cool']

     6、split函数 ----分割函数

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.split(r'd','one1two2three3four4')
    print(li) #打印输出['one', 'two', 'three', 'four', '']

    也可以结合copile函数:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    p = re.compile(r'd')
    li = p.split('one1two2three3four4')
    print(li) #打印输出['one', 'two', 'three', 'four', '']
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.split('[ab]','cabd')
    print(li)  #['c', '', 'd'],注意空字符串是连续分割的时候产生的

     split可以支持分组分隔,如下两个例子:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    st = 'hello alex bcd abcd lge acd 19'
    n = re.split('aw+',st,1)
    print(n)  #['hello ', ' bcd abcd lge acd 19']
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    st = 'hello alex bcd abcd lge acd 19'
    n = re.split('a(w+)',st,1)
    print(n)  #['hello ', 'lex', ' bcd abcd lge acd 19']

    五、关于rawstring(原生字符串)以及  符

       ------反斜杠后面跟元字符,去掉特殊功能变为普通字符;后面跟普通字符实现特殊功能;

    python反斜杠中作用:

    表示换行符, ASCII码是10

    表示回车符,ASCII码是13

    制表符

     表示退格字符

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    f = open(r"D:abc.txt")

    如果去掉r用:

    f = open(r"D:abc.txt")
    则会报错,因为a表示特殊意义。
    a是转义字符007,表示响铃符DEL
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('\\','abcd')
    print(li)

    分析一下“\\”,第一个斜杠是转义符,第二个斜杠是斜杠本身,第三个斜杠是转义符,第四个斜杠是斜杠本身。 
    有2点要清楚: 
    1.字符串里面表示斜杠就需要两个斜杠如“\” 
    2.正则表达式里的斜杠需要转意,是用“\”标示。 
    这样就比较好解释: 
    我们先要表示正则表达式里面的斜杠“\”,然后再用字符串表示出来。而这2个斜杠分别需要一个转义符,这样就成了4个斜杠在正则表达式里面表示 一个斜杠

    如果用原生字符串r,两个双斜杠就可以达到目的:

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall(r'\','abcd')
    print(li)

    第2个斜杠表示:python原生的字符串,传给正则后,正则用原生的进行转义。

    import re
    R = re.match(r'blow','blow') #或者用\b,python字符串中表示退格,所以传给正则时并不是而是退格,
    ##所以python字符串中需要转义把原值传给正则表达式
    #正则表达式把翻译为元字符单词边界
    print(R)

     六、其他及补充用法

    1、分组,如下面数据,匹配abc一次货多次的

    abcff

    abcabcaadd

    abcabcabc

    re: (abc)+

    2、|的用法

    张三|二丰   ----表示匹配张三或二丰

    张(三|二)丰   ----表示匹配张三丰或张二丰

    3、后向引用与非捕获,分组的延续引用

    后向引用:

    前面日期是入职日期,后面日期是离职日期,找出当年入职当年离职的日期

    正则表达式:(d{4}).+1.+

    1代指(d{4}),并且与(d{4})匹配的值完全相同

    在职日期
    2009-9-10 2009-10-4
    2008-9-10 2010-10-4
    2003-9-10 2003-11-4
    2001-3-10 2001-6-4
    1998-3-4 2012-1-1
    2012-10-1 2012-10-29
    2005-3 2005-8
    2004-2-13 2005-2-3
    2001年2月到2001年9月

     非捕获分组:分组默认的情况是有匹配组的,如果不想要匹配组那么可以在括号里面的最前面加?:,这样就可以去掉匹配组

    例如:(?:d{4}).+1.+

    4、[]的用法

    []表示括号中选中的若干字符之一

    [xyz]字符集合,匹配包含的任意一个字符

    [^xyz]负值字符集合。匹配未包含的任意一个字符

    [a-z]字符范围,匹配制定范围内的任意字符

    [^a-z]负值字符范围,匹配任何不在范围内的任意字符

    [0-9]字符范围,匹配制定范围内的任意字符

    [^0-9]负值字符范围,匹配任何不在范围内的任意字符

    例如:匹配单个单词

    How are you

    正则表达式:[a-zA-Z]+

    5、字符组去编号

    正则表达式:d+-d+[、. ]?

    1-11.判断语句之IF
    1-12、判断语句IF之多条件
    1-13判断语句之SELECT
    1-14、循环语句之DO...LOOP
    1-15、循环语句之DO...LOOP实例
    1-16循环语句之DO WHILE...LOOP
    1-2、宏在工作中的运用
    1-3、Excel VBA基础
    13-4、Excel VBA窗口介绍
    1-6.对象
    1-8、方法
    341-5、Excel VBA代码编写规则
    434-7、属性
    81-9、常量、变量

    6、首尾锚定

    ^   ----匹配字符串的开始位置

    $   ----匹配字符串的结束位置

    例如:以大写字母开头数字结尾的字符串

    正则表达式:^[A-Z].*d$

    7、汉字匹配

    un  匹配 n,其中n是四位十六进制数表示的Unicode字符

    汉字范围的第一个字符是“一”,其编码为:u4e00;最后一个字符为龢,其编码为:u9fa5

    汉字范围为:[一-龢]

    例如:提取字符串中的汉字

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    li = re.findall('[一-龢]','苹果apple橘子orange')
    print(li) #打印输出:['苹', '果', '橘', '子']

     8、零宽断言

    正向零宽断言,从左到右查看匹配:(?=...)

    负向零宽断言,与正向零宽断言相反,从左到右查看不匹配的位置:(?!...)

    零宽断言实际匹配的是一个位置,并不是实际字符或字符串。

    正则表达式:(?=I)    ----匹配到I前面的位置

    正则表达式:(!=I)    ----除了I前面的位置,其他位置都匹配到了

    例1:在参赛选手省份简称前面加(中)

    正则表达式:(?=[川吉云粤])

    参赛选手国籍 修改后
    李四-川            李四-(中)川
    陈升东-吉         陈升东-(中)吉
    竹下君-日本      竹下君-日本
    梁汉升-云         梁汉升-(中)云
    张三-川            张三-(中)川
    刘心兵-云         刘心兵-(中)云
    龙心-粤            龙心-(中)粤
    朴志熙-韩国      朴志熙-韩国
    成龙国-粤         成龙国-(中)粤

    例2:职务带总字的加上“高管”

    正则表达式::(?=副?总)   ---替换为:“:高管”

    张三:总经理              张三:(高管)总经理
    李四:车间主任           李四:车间主任
    陆一:总裁                 陆一:(高管)总裁
    周同生:经理              周同生:经理
    欧阳小小:副总经理      欧阳小小:(高管)副总经理
    林汤圆:主管              林汤圆:主管
    张山:副经理              张山:副经理

    例3:提取下面字符串中的金额

    正则表达式:d+.?d*(?=[元块])

    买2件衣服:600元,买12袋零食:89.5元,打游戏:98.5元
    买3本书:97块,买1双鞋子:408元,买日用品:389.7元
    买化妆品:305元,买1辆单车:670元,买1支笔:8元
    5个朋友过生日送礼物费用895.9元,买了1只小猫200块
    日用品:200元,请客吃饭:590元,借给朋友2000块,丢了100元。

     例4、负向零宽断言,给每个单子中间加-

    正则表达式:(?!^)(?=[a-z])

    pipe 管                 p-i-p-e 管

    9、懒惰与贪婪模式

    一般元字符量词都是贪婪模式,如果想变为懒惰模式则在元字符量词后面加?

    ?的用法:

    1)表示量词{0,1}

    2)表示非捕获型的匹配模式(?:)

    3)表示零宽断言(?=)  (?!)

    4)表示切换为懒惰模式:+?

    例如:字符串abcdef

    正则表达式:[a-z]+    匹配结果:[abcdef]

    正则表达式:[a-z]+?  匹配结果:[a,b,c,d,e,f]

    10、分组的妙用

    例1:下面字符串,提取部门和人数:

    财务部 26人 业务部 4人 回收站 2人 人事科 34人 生产车间 4567人

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    st = '财务部 26人 业务部 4人 回收站 2人 人事科 34人 生产车间 4567人'
    li = re.findall('([一-龢]+) (d+人)',st)
    print(li)
    #打印输出:
    #[('财务部', '26人'), ('业务部', '4人'), ('回收站', '2人'), ('人事科', '34人'), ('生产车间', '4567人')]

    例2:下面字符串,提取姓名、身份证号、性别、年龄、籍贯

    丁红梅 130981198206188284 女 30 河北省 沧州市 泊头市 蔚然 632324196704122182 女 45 青海省 黄南藏族自治州 河南蒙古族自治县 宓香菱 371103196505169263 女 47 山东省 日照市

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    st = '丁红梅 130981198206188284 女 30 河北省 沧州市 泊头市 蔚然 632324196704122182 女 45 ' 
         '青海省 黄南藏族自治州 河南蒙古族自治县 宓香菱 371103196505169263 女 47 山东省 日照市 '
    li = re.findall('(S+) (S+) (S) (d+)(( S+){1,3})',st)
    print(li)
    #打印输出:
    #[[('丁红梅', '130981198206188284', '女', '30', ' 河北省 沧州市 泊头市', ' 泊头市'), 
    # ('蔚然', '632324196704122182', '女', '45', ' 青海省 黄南藏族自治州 河南蒙古族自治县', ' 河南蒙古族自治县'), 
    # ('宓香菱', '371103196505169263', '女', '47', ' 山东省 日照市', ' 日照市')]

     例3:分组包含分组的情况

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    st = 'hello alex alex bac abcd 19'
    r = re.findall('((a)(w+))',st)
    print(r)  #[('alex', 'a', 'lex'), ('alex', 'a', 'lex'), ('ac', 'a', 'c'), ('abcd', 'a', 'bcd')]

     例4:利用正则表达式计算:(参考split分组)

    1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )的值
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    import re
    def calculate(exp):
        return eval(exp)
    
    st = '1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
    while True:
        print(st)
        li = re.split('(([^()]+))',st,1)
        if len(li) == 3:
            # left = li[0]
            # middle = li[1]
            # right = li[2]
            left,middle,right = li  #本句代码相当于上面的三句注销的代码
            middle_result = calculate(middle)
            st = left + str(middle_result) + right
        else:
            result = calculate(st)
            print(result)
            break
    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    n1,n2 = 3,4
    print(n1,n2)  #3 4
    
    li = [11,22,33]
    n1,n2,n3 = li
    print(n1,n2,n3)  #11 22 33
  • 相关阅读:
    Zstack中任务,事件,消息之间的关系
    Zigbee折腾之旅:(一)CC2530最小系统
    计算机中原码,反码,补码之间的关系
    Python3
    Python3
    Python3
    【基础】强软弱虚引用
    SpringBoot上传文件时MultipartFile报空问题解决方法
    Mockito中的@Mock和@Spy如何使用
    Vim 多行剪切、复制和删除
  • 原文地址:https://www.cnblogs.com/sunshuhai/p/6395920.html
Copyright © 2020-2023  润新知