2018-10-23 Day18 正则表达式

1.正则表达式语法

from re import fullmatch
from re import match

正则表达式是用来匹配或者描述字符串的工具

用处:
a.判断输入的字符串是否是邮箱/手机号码。是否ip地址等 等
b.提取满足条件的字符串
c.字符串替换

python中通过re模块相应的方法来支持正则表达式的匹配、查找、替换等功能
match --> 匹配
fullmatch(正则表达式字符串, 字符串) --> 完全匹配,查看正则表达式和字符串是否完全匹配
正则表达式: 就是一个字符串,字符串中是正则表达式语法, r"正则表达式"
正则表达式中包含两个部分, 一个是正则语法对应的字符, 二个是普通字符

1. .匹配任意字符 --> 一个点只匹配一个任意字符
  • 匹配一个长度是3的字符串, 第一个字符是a, 第二个字符是任意字符, 最后一个字符是b
re_str = r'a.b'
print(fullmatch(re_str, 'acb'))
  • 匹配一个长度是4,第一个字符是a,第二个字符是b最后两个字符是任意字符的字符串
re_str1 = r'ab..'
print(fullmatch(re_str1, 'ab1a'))
2. \w --> 匹配字母数字下划线 一个\w匹配的是一个字符
  • 匹配一个第一个字符是数字、字母或者下划线, 后面三个字符是任意字符的字符串
re_str2 = r'\w...'
print(fullmatch(re_str2, '_d +'))
3. \s --> 匹配任意空白字符, 所有能产生空白的字符
re_str4 = r'a\sb'
print(fullmatch(re_str4, 'a\tb'))
4. \d --> 匹配数字字符
re_str5 = r'\d\d\d'
print(fullmatch(re_str5, '555'))
5. \b --> 检测边界,一个\b不会去匹配一个字符,而是单纯的检测\b出现的位置是否是单词边界
  • 单词边界: 字符串开始或者结尾,空格、换行、\t、逗号等等可以将两个单词隔开的字符都是单词边界
re_str6 = r'\d..\b'
print(fullmatch(re_str6, '4ad'))
re_str7 = r'abc\ba33' --> 没有字符串能匹配
re_str7 = r'abc/b/sa33' #--> 匹配一个字符串前三位是abc,第四位是空格,后三位是a33,并且要求c字符后面是单词边界
print(fullmatch(re_str7, 'abc\na33'))
6. ^ --> 检测是否是字符串开头
re_str8 = r'^\d\d\d'    # 判断一个字符串是否是三个数字开头
print(fullmatch(re_str8, '333'))
7. $ --> 检测是否是字符串结尾
re_str9 = r'abc$'
print(fullmatch(re_str9, 'abc'))
8. \W --> 匹配非字母、数字下划线
re_str10 = r'\Wabc'
print(fullmatch(re_str10, '*abc'))
9. \S --> 匹配非空白字符
re_str11 = r'\S\d\d\d'  # 匹配第一个是非空白字符,后面三个数字
print(fullmatch(re_str11, '+333'))
10. \D --> 匹配非数字字符
re_str12 = r'\D\s\w'
print(fullmatch(re_str12, 'e r'))
11. \B --> 检测非边界
re_str13 = r'abc\B5b'
print(fullmatch(re_str13, 'abc5b'))
12. [] --> 匹配中括号中出现的任意一个字符
  • [字符集] --> 匹配一个字符,这字符是字符集中的任意一个字符
  • [字符1-字符2] --> 匹配一个字符,这个字符是Unicode编码值在字符1到字符2中的任意字符要求字符1小于字符2
[\u0031-\u0039] --> 使用原始字符,匹配0~9的数字
[\u4E00-\u9fa5] --> 匹配所有的汉字

注意: -在中括号中,如果放在两个字符之间表示范围,表示减号就得放在字符前面或者后面

re_str14 = r'[abcd]aaa'     # 匹配第一个字符是abcd中的任意单个字符,后面三个是aaa的字符串
print(fullmatch(re_str14, 'daaa'))

re_str15 = r'[1-4]\d\d\d'   # 检测第一位字符串是1~4,后面三位是任意数字的字符串
print(fullmatch(re_str15, '2789'))

re_str16 = r'[\u0031-\u0039]aa'
print(fullmatch(re_str16, '8aa'))

re_str17 = r'[\u4E00-\u9fa5][\u4E00-\u9fa5][\u4E00-\u9fa5]'
print(fullmatch(re_str17, '哈哈哈'))

re_str18 = r'18208333774'
print(fullmatch(re_str18, '18208333774'))

# 匹配一个字符是字母数字下划线或者空白
re_str19 = r'[\w\s]'
print(fullmatch(re_str19, '_'))
13. [^] 匹配一个不在[]中的字符集中的任意字符,注意''只能放在中括号最前面
re_str20 = r'[^abc]...'     # 匹配第一个字符不是abc任意一个,其他为任意字符的字符串
print(fullmatch(re_str20, 'd123'))
re_str21 = r'[^1-9]...'     # 第一个字符不能是1-9
print(fullmatch(re_str21, '0123'))

2.正则表达式匹配次数的符号

from re import fullmatch
1. * --> 匹配0次或者多次,注意*前面必须要有个字符
str1 = r'\d*'       # 匹配0位或者多位的数字字符串
print(fullmatch(str1, ''))
print(fullmatch(str1, '2132'))
用正则表达式来检测一个标识符是否符合要求: 数字字母下划线组成,数字不开头
str2 = r'[a-zA-Z_]\w*'
print(fullmatch(str2, 'a2sd'))
2. + --> 匹配一次或者多次,注意+前面必须要有字符
str3 = r'\d+abc'        # 匹配前面一个或者多个数字,结尾abc的字符串
print(fullmatch(str3, '213abc'))
3. ? --> 匹配0次或者1次
str4 = r'a?123'     # 匹配a123  123

# 练习: 写一个正则表达式匹配所有的整数(123, -2334, +9)
str5 = r'[+-]?[1-9]\d*'
print(fullmatch(str5, '+20213'))
4. {} --> 指定次数
{n} --> 匹配n次
{m,n} --> 匹配m~n次
{m,} --> 至少匹配m次
{,n} --> 最多匹配n次

str6 = r'\d{3}'     # 匹配数字三次
print(fullmatch(str6, '123'))

str7 = r'\d{3,}'
print(fullmatch(str7, '123'))

str8 = r'[a-z]{2,5}'
print(fullmatch(str8, 'daksk'))

# 判断密码是否符合要求: 密码是由数字和字母组成,并且位数是6~16位
str_pw = r'[0-9a-zA-Z]{6,16}'
print(fullmatch(str_pw, 'sandkjhi12'))

3.分支和分组

from re import fullmatch
import re
1. | --> 分支
  • 条件1|条件2 --> 先用条件1去匹配,如果匹配成功,就结束,如果条件1匹配失败,用条件2去匹配
    注意: 如果条件1匹配成功就不会用条件2再去匹配
re_str = r'[a-z]{3}|[A-Z]{3}'   # 会把|的前面和后面作为一个整体条件
print(fullmatch(re_str, 'abc'), fullmatch(re_str, 'ABC'))

re_str = r'abc|d'   # |前面和后面作为整体条件,要么abc要么d
print(fullmatch(re_str, "abc"), fullmatch(re_str, 'd'))
2. () --> 分组
  • a.将括号中的内容作为一个整体进行操作 --> 'abc' + W|H|Y

  • b.捕获 --> 使用带括号的正则表达式匹配成功后只获取()中的内容

  • c.重复 --> 在正则表达式中可以通过\数字来重复前面()中匹配到的结果,数字代表的是第几个括号

re_str = r'abc(W|H|Y)'
print(fullmatch(re_str, 'abcW'))

# 需要一个数字加一个字母出现三个的字符串
# 组合
re_str = r'(\d[a-zA-Z]){3}'
print(fullmatch(re_str, '1a2b3c'))

# 捕获
re_str = r'\d{3}abc'
print(fullmatch(re_str, "333abc"))      # 将满足正则表达式的式子返回列表
print(re.findall(re_str, '213abc233abc'))

re_str = r'(\d{3})abc'      # 捕获时只取括号内的内容
print(re.findall(re_str, '213abc233abc'))

# 重复
re_str = r'([a-z]{3})-(\d{2})\1\2'
print(re.fullmatch(re_str, 'ccc-22ccc22'))
3.正则表达式转义字符

正则表达式可以通过在特殊符号前加\来使特殊符号没有功能 . + * ? ^
. --> 任意字符 . --> 字符.

  • --> 匹配一次或者多次 + --> 字符+
    注意: 在中括号中,特殊字符可以不用\转义,-号除外,\在哪儿都需要转义
    ()在外边需要转义,放在中括号内不需要转义
re_str = r'\d{2}\.\d{2}'
print(fullmatch(re_str, '12.22'))

re_str = r'\d\+\d'
print(fullmatch(re_str, '3+7'))

4.re模块中的函数

import re
1. compile

compile(正则表达式字符串) --> 将正则表达式字符串转化成正则表达式对象,先转化为对象,之后调用fullmatch只需要传1个参数,直接传字符串

re_object = re.compile(r'\d+')
print(re_object)
print(re_object.fullmatch("21312"))
2. fullmatch/match

fullmatch(正则表达式字符串,需要去匹配的字符串) --> 用正则表达式去完全匹配字符串,返回匹配对象
match(正则表达式字符串, 字符串) --> 匹配字符串开头,看字符串开头是否满足要求,返回匹配对象或者None

result = re.fullmatch(r'\d[a-zA-Z]+', '2jk')
print(result, type(result))
1.span() --> 获取的是匹配成功的开始下标和结束下标(取不到的)
print(result.span())
print(result.start())       # 获取匹配到的开始下标
print(result.end())         # 获取匹配到的结束下标后的下标
print('=============')
2.group(下标) --> 获取匹配的结果,下标默认值为0

group() --> 获取正则表达式完全匹配的结果
group() --> 有下标的时候,获取正则表达式中第下标个分组匹配到的结果

print(result.group())
3.search(正则表达式, 字符串) --> 查找字符串中满足正则表达式的第一个字符串,返回值是匹配对象或者None
result = re.search(r'(\d)[a-zA-Z]+', 'uakd3abcd_sjk3k')
print(result)
print(result.group(1))

# 练习: 用search匹配出一个字符串中所有的数字字符串
str1 = "ajkd34dajsk89sajdk23dska9akd567"
re_str = r'\d+'
result = re.search(re_str, str1)

while result:
    print(result)
    str1 = str1[result.end():]
    result = re.search(re_str, str1)
4.string --> 获取被匹配的原字符串
5.findall

findall(正则表达式,字符串) --> 获取字符串中满足正则表达式所有的子串,返回结果位一个列表
注意: 如果正则表达式中有分组,取值的时候只取分组中匹配到的结果
如果有多个分组,会讲每个分组匹配到的结果作为一个元组的元素,将元组变为列表的元素

re_str = r'(\d+)k([a-d]+)'
str1 = 'abc34kmasmd8923kabc0kasdk89kaa'
result = re.findall(re_str, str1)
print(result)       # [('8923', 'abc'), ('0', 'a'), ('89', 'aa')]
5.finditer

finditer(正则表达式,字符串) --> 查找所有满足正则表达式条件的子串,以迭代器返回,并且迭代器中的元素是匹配对象

re_str = r'\d+'
str1 = 'abc34kmasmd8923kabc0kasdk89kaa'
result = re.finditer(re_str, str1)
print(result)
for i in result:
    print(i)
6.split

split(正则表达式,字符串) --> 把字符串按照满足正则表达式条件的子串进行分割

str1 = 'abs-d1k+smd3fh4+fcj59aj-d22'
re_str = r'[+-]'
result = re.split(re_str, str1)
print(result)
7.sub

sub(正则表达式,被替换字符串,字符串) --> 将字符串中满足正则表达式条件的子串替换成被替换的字符串

re_str = r'\d+'
str1 = 'asd55f5gh22j1sad3fj4'
rep = '*'
result = re.sub(re_str, rep, str1)
print(result)


str1 = '智   障,你在干嘛?'
result = re.sub(r'傻\s*叉|逼\s*|fuck|妈\s*的|智\s*障', "*", str1)
print(result)

5.歌词解析

需求: 播放指定歌曲的时候,给一个时间,能够把这首歌对应这个时间的词返回,面向对象: 找一个类,让它拥有解析歌词的功能

class Lyrics:
    """歌词类"""
    def __init__(self, time='', word=''):
        self._time = time
        self.word = word

    @property
    def time(self):
        return self._time

    @time.setter
    def time(self, value):
        fen = float(value[1:3])
        m = float(value[4:])
        self._time = fen*60 + m

    def __gt__(self, other):
        return self._time > other._time

    def __repr__(self):
        return str(self.__dict__)


class LyricsAnalysis:
    """
    歌词解析类
    name对应的是解析的歌名
    """
    def __init__(self, name):
        self.__name = name
        self.__all_lyric = [] # 保存当前歌名解析出来的所有词

    # 分离歌词和时间
    def __split_t_ric(self, line):
        # 时间 <-> 歌词
        line_list = line.split(']')
        # print(line_list)
        # 获取每一行的词
        word = line_list[-1]
        # 遍历获取每一行的时间
        for time in line_list[:-1]:
            # 根据时间和歌词创建歌词对象
            ly_obj = Lyrics(word=word)
            ly_obj.time = time
            self.__all_lyric.append(ly_obj)

    # 根据时间获取歌词
    def get_lyrics(self, time: int):
        """
                读文件内容
                解析文件
                找到时间
                将时间返回
                """

        # 判断之前是否已经解析过
        if self.__all_lyric:
            # 解析过根据时间取值
            for item in self.__all_lyric:
                if item.time < time:
                    return item.word

        try:
            with open('./files/' + self.__name + '.txt', 'r', encoding='utf-8') as f:
                line = f.readline()
                while line:
                    # print(line)
                    self.__split_t_ric(line)
                    line = f.readline()
                # 排序
                self.__all_lyric.sort(reverse=True)
                # 根据时间取值
                for item in self.__all_lyric:
                    if item.time < time:
                        return item.word

        except FileNotFoundError:
            print("没有相应的歌词")


ly_lan = LyricsAnalysis('蓝莲花')
print(ly_lan.get_lyrics(10))
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容