菜鸟学习Python(第十期)~~正则表达式(四)

作者: KangSmit的算法那些事儿 | 来源:发表于2019-10-06 19:38 被阅读0次

继续上一次正则表达式学习~~
点击下面蓝色字体可回看往期知识点:

Python(第十期)~~正则表达式(一)
Python(第十期)~~正则表达式(二)
Python(第十期)~~正则表达式(三)

回顾:
在正则表达式中,需要注意的是,大家在写编程的时候,可能会注意美观,可能会多加一些空格,但是在正则表达式里面,你千万不能加空格。例如:

>>> import re
>>> re.search(r'(love){1,5}', 'I love lovelovelove')
<re.Match object; span=(2, 6), match='love'>
>>> re.search(r'(love){3,5}', 'I love lovelovelove')
<re.Match object; span=(7, 19), match='lovelovelove'>
>>> re.search(r'(love){0,1}', 'I love lovelovelove')
<re.Match object; span=(0, 0), match=''>
>>> #下面加空格
>>> re.search(r'(love){1, 5}', 'I love lovelovelove')
>>> #显然是None

这是因为空格会被解析为一个正则表达式。
几个特殊的等价关系
①、星号(*):匹配前面的子表达式零次或多次,等价于 {0,};
②、加号(+):匹配前面的子表达式一次或多次,等价于 {1,};
③、问号(?):匹配前面的子表达式零次或一次,等价于 {0,1}。

14、贪婪 和 非贪婪

值得注意的是,正则表达式默认是启用 贪婪 的模式来进行匹配的,那什么是 贪婪 呢?
简单的是说贪婪就是贪心,也就是说,只要在符合的条件下,它会尽可能多的去匹配,例如回顾前面的

>>> re.search(r'(love){1,5}', 'I love youyouyou')
<re.Match object; span=(2, 6), match='love'>
>>> re.search(r'(you){1,5}', 'I love youyouyou')
<re.Match object; span=(7, 16), match='youyouyou'>
>>> re.search(r'(you){4,5}', 'I love youyouyou')
>>> re.search(r'(you){3,5}', 'I love youyouyou')
<re.Match object; span=(7, 16), match='youyouyou'>

就会直接匹配到3个 youyouyou。
下面给出另一个例子:

>>> import re
>>> re.search(r"<.+?>", s)
<re.Match object; span=(0, 6), match='<html>'>
>>> re.search(r"<.+>", s)#没有问号不是我们想要的结果
<re.Match object; span=(0, 43), match='<html><title> I love you.com</title></html>'>

源码剖析:
特别地,在正则表达式中,<.+> 表示以 < 开头,以 > 结尾,重复 . 号 1次或多次。最后匹配了字符串全部。

对于贪婪来说,它会在条件符合的情况下尽可能多的去匹配,既然是这样,我们就必须启用 非贪婪模式才可以,那么非贪婪模式怎么样启用呢?

值得关注的是,在表示重复的元字符后面再加上一个“?”问号,这时候,问号就不代表0次或1次了,而是表示启用非贪婪模式(如上述代码的最后两行)

15、反斜杠(\) + 字母 等同于 特殊字符的含义

(1)、\序号,其中序号就是数字:

①、引用序号对应的子组所匹配的字符串,此时序号的范围是 1~99,子组的序号是从 1 开始计算。

②、如果序号是以 0 开头,或者 3 位数字的长度。那么不会被用于引用对应的子组,而是用于匹配八进制数字所表示的ASCII 码值对应的字符。
上述在前期已经提到,这里将不再重复。

(2)、\A :这个符号在默认情况下和 托字符(^)是一样的,都是匹配输入字符串的开始位置。
源码剖析:
也就是说,要是前面是 \A 或者 ^ 符号,那么这个字符就必须出现在字符串的开头,才能算是匹配。

(3)、\Z:这个符号在默认情况下和 美元符号($)是一样的,都表示匹配输入字符串的结束位置。

上述都是在默认情况下进行的,但不是说完全一样的。因为在正则表达式中还有一个 编译标志的设置。
例如:如果说你设置了一个 re.MULTILINE 标志,那么托字符(^)也匹配换行符之后的位置,同时,美元符号($)也匹配换行符之前的位置。

但是呢,无论你设不设置这个标志,这个 \A 和 \Z 都只能匹配字符串的开头 和 结束 位置。

像这种匹配位置的字符,我们给它们一个名字,叫做 临框断言,言外之意就是它们不会匹配任何字符,它们只用于定位一个位置。

(4)、\b 它是匹配一个单词的边界,单词被定义为 Unidcode 的字母数字或下横线字符。举个例子:

>>> import re
>>> re.findall(r"\bYOU\b", "YOU.com!YOU_com!(YOU)")
['YOU', 'YOU']
>>> re.findall(r"\BYOU\B", "YOU.com!YOU_com!(YOU)")
[]

源码剖析:
上面只找到了两个 YOU,你知道它哪一个YOU没有找到吗?(事实上是 YOU_com 中的YOU),因为下划线也被认为是单词字符,不是边界。点号(.)感叹号(!)、括号都被认为是单词边界。

(5)、\B,其实就是与 \b 相反,匹配非单词边界(如上述代码中的最后一行)。

(6)、\d:
① 对于 Unicode(str 类型)模式:匹配任何一个数字,包括 [0-9] 和其他数字字符;如果开启了 re.ASCII 标志,就只匹配 [0-9]。

② 对于 8 位(bytes 类型)模式:匹配 [0-9] 中任何一个数字。

(7)、\D:与 \d 相反,匹配任何非 Unicode 的数字;如果开启了 re.ASCII 标志,则相当于匹配 [^0-9]。

(8)、\s :
①对于 Unicode(str 类型)模式:匹配 Unicode 中的空白字符(包括 [ \t\n\r\f\v] 以及其他空白字符);如果开启了 re.ASCII 标志,就只匹配 [ \t\n\r\f\v]

② 对于 8 位(bytes 类型)模式:匹配 ASCII 中定义的空白字符,即 [ \t\n\r\f\v]

(9)、\w:① 对于 Unicode(str 类型)模式:匹配任何 Unicode 的单词字符,基本上所有语言的字符都可以匹配,当然也包括数字和下横线;如果开启了 re.ASCII 标志,就只匹配 [a-zA-Z0-9_]。
例如:

>>> re.findall(r"\w", "我爱YOU3 (love_YOU.com!)")
['我', '爱', 'Y', 'O', 'U', '3', 'l', 'o', 'v', 'e', '_', 'Y', 'O', 'U', 'c', 'o', 'm']
>>> re.findall(r"\W", "我爱YOU3 (love_YOU.com!)")
[' ', '(', '.', '!', ')']

除了 空格 括号 点号 感叹号,其它的汉字、字母、下横线、数字 都是单词字符。

(10)、\W :其实就是与 \w 相反, 匹配任何非 Unicode 的单词字符,;如果开启了 re.ASCII 标志,则相当于 [^a-zA-Z0-9_]

此外,正则表达式还支持大部分 Python 字符串的转义符号:\a,\b,\f,\n,\r,\t,\u,\U,\v,\x,\

16、编译正则表达式

在正则表达式的编译中,若你要重复地使用某个正则表达式,那么你可以先把该正则表达式编译成模式对象。

可以打开Python3.7.4解释器的文档(在Help中的doc或F1), 然后搜索e.compile() 就在正则表达式中(Compiling Regular Expressions),并且给出了例子。

可以直接打开Python官网的中文文档:

https://docs.python.org/zh-cn/3/library/re.html?highlight=re%20complie


下面我们再试一试使用 re.compile() 方法来编译表达式

>>> x = re.compile(r"[A-Z]")
>>> type(x)#x的类型
<class 're.Pattern'>

把正则表达式 [A-Z] 进行编译,赋值给 一个变量 x,这个变量 x就是一个模式对象。我们可以直接使用 x 进行 search() 方法 和 findall() 方法 的使用:

>>> x.search("I love you")
<re.Match object; span=(0, 1), match='I'>
>>> x.findall("I love you")
['I']
每日三道题, 笔试面试不吃亏:

题目13:将一个正整数分解质因数。例如:输入90,打印出90=233*5。

分解质因数:
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。如30=2×3×5 。分解质因数只针对合数。

程序分析:
对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:
(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
(2)如果n<>k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数n,重复执行第一步(1)。
(3)如果n不能被k整除,则用k+1作为k的值,重复执行第一步。

while 1:
    n = int(input('请输入一个整数:'))
    print('%d='%n,end='')
    while n>1:
        for i in range(2,n+1):
            if n%i==0:
                n=int(n/i)
                if n==1:
                    print('%d'%i,end='')
                else:
                    print('%d*'%i,end='')
                break
    print()

from math import sqrt
while 1:
    n=int(input('请输入整数:'))
    print ("%d = " %n , end = '')
    while 1:
        for i in range(2,int(sqrt(n)+1)):
            if n%i==0:
                print('%d*'%i,end='')
                n=int(n/i)
                break
        else:
            print(n)
            break

def prime(n):
    L=[ ]
    while n>1:
        for i in range(2,n+1):
            if n % i ==0:
                n = int(n/i)
                L.append(i)
                break
    return L
while 1:
    s = input('请输入一个正整数:')
    if s.isdigit() and int(s)>0:
        print(s,'=','*'.join([str(x) for x in prime(int(s))]))#*.join(sequence)用*号连接元素序列
    else:
        print('请输入一个正整数:')

执行结果:

题目14:利用条件运算符的嵌套来完成此题:
学习成绩>=90分的同学用A表示,
60-89分之间的用B表示,
60分以下的用C表示。

程序分析:
程序分析:(a>b)?a:b这是条件运算符的基本例子。

score = int(input('输入分数:'))
print("A" if score>89 else('B' if score>59 else 'C'))

while 1:
    score = int(input('输入分数:'))
    mark = [90,60,0]
    result=['A','B','C']
    for i in range(0,3):
        if score>=mark[i]:
            print('%d属于:%s'%(score,result[i]))
            break

def grade(score):
    if score >=90:
        print("A")
    elif score>=60:
        print("B")
    else:
        print("C")
while 1:
    score = int(input('输入分数:'))
    grade(score)

执行结果:


题目15:输出指定格式的日期。
程序分析:使用 datetime 模块。

import time
print('当前时间戳:',time.time())
    #当前时间戳
print('获取当前本地时间:',time.localtime())
    #获取当前本地时间
print('格式化可读时间模式:',time.asctime())
    #格式化可读时间模式
print('格式化日期:',time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
    #格式化日期: 2019-10-06 19:35:38

import datetime
print('当前年月日:',datetime.date.today())
    #当前年月日
print('格式化日期:',datetime.date.today().strftime('%d/%m/%Y'))
    #格式化日期
print(datetime.date(1941,1,5))
    #1941-01-05

执行结果:


扫码关注我,一起交流学习

相关文章

网友评论

    本文标题:菜鸟学习Python(第十期)~~正则表达式(四)

    本文链接:https://www.haomeiwen.com/subject/zerypctx.html