python(正则表达式)

通配符的使用

通配符:
    *: 表明任意多个字符
    ?: 表明单个字符
    .: 当前目录
    ..:当前目录的上一级目录
    [0-9]: 单个字符为0~9
    [a-z]:
    [A-Z]
    [A-Za-z]
    [0-9A-Za-Z]

    [[:digit:]]:单个数字
    [[:upper:]]:单个大写字符
    [[:lower:]]:单个小写字符
    [[:space:]]:单个空格
# 获取当前目录下以一个数字开头以.任意结尾的文件
glob.glob('./[0-9].*')
# 以任意多个字符开头以.gif结尾的文件
glob.glob('*.txt')
# 以任意单个字符开头以.gif结尾的文件
glob.glob('?.txt')
# 任意目录下的以任意多个字符开头以.txt结尾的文件,采用递归方式
glob.glob('**/*.txt', recursive=True)
# 当前目录下的全部目录,采用递归方式
glob.glob('./**/', recursive=True)

在这里插入图片描述

import os
import glob

files1 = [file for file in os.listdir('.') if file.endswith('.conf')]
# 获取当前目录全部以.conf结尾的文件;
files2=  glob.glob('./*.conf')
print(files1)
print(files2)

在这里插入图片描述

正则表达式的经常使用方法

match方法:

match尝试从字符串的起始位置开始匹配
  • 若是起始位置没有匹配成功, 返回None;
  • 若是起始位置匹配成功, 返回一个对象, 经过group方法获取匹配的内容;
# re:regular express 正则表达式
aObj = re.match(r'we', 'wetoshello')
print(aObj)
print(aObj.group())

# \d 单个数字
# \D \d的取反 , 除了数字以外
bObj = re.match(r'\d', '1westos')
if bObj:
    print(bObj.group())

bObj = re.match(r'\D', '_westos')
if bObj:
    print(bObj.group())

在这里插入图片描述

findall方法:

findall会扫描整个字符串, 获取匹配的全部内容;
res = re.findall(r'\d\d', '阅读数为2 点赞数为10')
print(res)

在这里插入图片描述

search方法:

search会扫描整个字符串, 只返回第一个匹配成功的内容的SRE对象;
resObj = re.search(r'\d', '阅读数为8 点赞数为10')

if resObj:
    print(resObj.group())

在这里插入图片描述

06_正则表达式的特殊字符类

字符类:
[ ]匹配括号内多个字符中的任意一个字符
[^ ]表示匹配除了括号内的任意一个字符
  • [pP]ython
  • westos[pP]
  • [aeiou]
  • [a-z]:匹配任意一个小写字母
  • [A-Z]:匹配任意一个大写字母
  • [a-zA-Z0-9]:匹配任意一个小写或大写字母或数字
  • [^aeiou]
  • [^0-9]:匹配除了数字的任意一个字符

特殊字符类:

  • .: 匹配除了\n以外的任意字符; [.\n]
  • \d: digit–(数字), 匹配一个数字字符, 等价于[0-9]
  • \D: 匹配一个非数字字符, 等价于[^0-9]
  • \s: space(广义的空格: 空格, \t, \n, \r), 匹配单个任何的空白字符;
  • \S: 匹配除了单个任何的空白字符;
  • \w: 字母数字或者下划线, [a-zA-Z0-9_]
  • \W: 除了字母数字或者下划线, [^a-zA-Z0-9_]
^: 在[]前面表示以什么开头,在[]里面表示除括号内字符以外的任意一个字符^: 以什么开头
$: 以什么结尾
$: 以什么结尾
import re


# 匹配数字
# pattern = r'\d'
pattern = r'[0-9]'
string = "hello_1$%"
print(re.findall(pattern, string))


# 匹配字母数字或者下划线;
# pattern = r'\w'
pattern = r'[a-zA-Z0-9_]'
string = "hello_1$%"
print(re.findall(pattern, string))

# 匹配除了字母数字或者下划线;
# pattern = r'\W'
pattern = r'[^a-zA-Z0-9_]'
string = "hello_1$%"
print(re.findall(pattern, string))

# .: 匹配除了\n以外的任意字符; [.\n]
print(re.findall(r'.', 'hello westos\n\t%$'))

在这里插入图片描述

北美电话号码的合法性

问题描述:
    北美电话的经常使用格式:(eg: 2703877865)
            前3位: 第一位是区号以2~9开头 , 第2位是0~8, 第三位数字可任意;
            中间三位数字:第一位是交换机号, 以2~9开头, 后面两位任意
            最后四位数字: 数字不作限制;
# 传统正则
pattern = r'[2-9][0-8]\d[2-9]\d\d\d\d\d\d'
# 能够利用重复符号的方式
pattern = r'[2-9][0-8]\d[2-9]\d{6}'
import re

def is_valid(pattern,tel):
    telObj=re.search(pattern,tel)
    if telObj:
        print('%s合法' %(tel))
    else:
        print('%s不合法' %(tel))

if __name__ == '__main__':
    pattern = r'[2-9][0-8]\d[2-9]\d{6}'
    is_valid(pattern,'2777777777')
    is_valid(pattern,'1777777777')

在这里插入图片描述

指定字符出现的次数

匹配字符出现次数:

*: 表明前一个字符出现0次或者无限次;    \d*,  .*
 +: 表明前一个字符出现一次或者无限次;     d+
 ?: 表明前一个字符出现1次或者0次;   假设某些字符可省略, 也能够不省略的时候使用,即去贪婪

第二种方式:

{m}: 前一个字符出现m次;
{m,}: 前一个字符至少出现m次;  * == {0,}; + ==={1,}
{m,n}: 前一个字符出现m次到n次; ? === {0,1}
import re

# *: 表明前一个字符出现0次或者无限次;    \d *,.*
print(re.findall(r'\d*', '234'))
print(re.findall(r'.*', 'hello223%'))
print(re.findall(r'd*', 'ddhello223%'))


#     +: 表明前一个字符出现一次或者无限次;     d+
print(re.findall(r'd+', ''))
print(re.findall(r'd+', 'dddderrttt'))
print(re.findall(r'\d+', '阅读数: 8976 点赞数:900'))

#  ?: 表明前一个字符出现1次或者0次;   假设某些字符可省略, 也能够不省略的时候使用
# 2019-10
print(re.findall(r'\d+-?\d+', '2019-10'))
print(re.findall(r'\d+-?\d+', '201910'))
print(re.findall(r'\d{4}-?\d{1,}', '2019-1'))
print(re.findall(r'\d{4}-?\d{1,2}', '2019-10'))
print(re.findall(r'\d+-?\d+', '201910'))

在这里插入图片描述

匹配电子邮箱的规则

练习: 匹配一个163邮箱;(xdshcdshvfhdvg@qq.com)  --- 若是想在正则里面匹配真实的. , \.
      xdshcdshvfhdvg(能够由字母数字或者下划线组成, 可是不能以数字或者下划线开头; 位数是6-12之间)

在这里插入图片描述

编译正则表达式

当须要匹配大量数据时,采用现编译正则表达式能够节省大量的时间html

转义的实现:
 + , ? , (), *, . 必定要转义
 () ---有本身的用法, 对()进行转义
 . ---有本身的用法, 对.进行转义
"""
要求:北美电话号码的格式为:
			1234567890
			123-456-7890
			123.456.7890
			123 456 7890
			(123) 456 7890
"""
import random
import re
import time


def timeit(f):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = f(*args, **kwargs)
        end_time = time.time()
        print("%s执行时间: %fs" % (f.__name__, end_time - start_time))
        return res

    return wrapper




def createPhone():
    with open('phoneText.txt', 'w') as f:
        for i in range(1000000):
            # 生成一个随机的电话号码;
            phone = "".join([str(random.randint(0, 9)) for i in range(10)])
            f.write(phone + '\n')




@timeit
def use_compile():
    pattern = r"\(?[2-9][0-8]\d\)?[-\.\s]?[2-9]\d{2}[-\.\s]?\d{4}"
    compilePattern = re.compile(pattern)

    with open('phoneText.txt') as f:
        for line in f:
            phone = line.rstrip()
            res = re.search(compilePattern, phone)
            if res:
                return True
            return False


@timeit
def no_compile():
    pattern = r"\(?[2-9][0-8]\d\)?[-\.\s]?[2-9]\d{2}[-\.\s]?\d{4}"
    # pattern = r'\d{10}'
    with open('phoneText.txt') as f:
        for line in f:
            phone = line.rstrip()
            res = re.search(pattern, phone)
            if res:
                return True
            return False


if __name__ == '__main__':
    # createPhone()
    no_compile()
    use_compile()

在这里插入图片描述

正则表达式之分组操做

表示分组

  • | : 匹配| 左右任意一个表达式便可;
  • (ab): 将括号中的字符做为一个分组
  • \num: 引用分组第num个匹配到的字符串
  • (?P): 分组起别名
  • (?P=name) : 引用分组的别名
import re

print(re.findall(r'westos|hello', "hellowestos"))
# 进行分组的时候, findall方法只返回分组里面的内容;
print(re.findall(r'(http|https)(.+)', 'http_hello'))

# search
sreObj = re.search(r'(http|https)(.+)', 'http_hello')
if sreObj:
    # group方法会返回匹配的全部内容;
    print(sreObj.group())
    # groups方法返回分组里面的内容;
    print(sreObj.groups())



# 需求: 获取标签里面的文字, 并判断标签是否成对出现?
htmlStr = "<html><p>welcome to westos!</p></html>"
pattern = r'<(\w+)><(\w+)>(.+)</\2></\1>'
print(re.findall(pattern, htmlStr))
print(re.findall(pattern, htmlStr)[0][2])

# 需求: 分组起别名?
htmlStr = "<html><p>welcome to westos!</p></html>"
pattern = r'<(?P<FirstTag>\w+)><(?P<SecondTag>\w+)>(?P<Text>.+)' \
          r'</(?P=SecondTag)></(?P=FirstTag)>'
print(re.findall(pattern, htmlStr))
sreObj = re.search(pattern, htmlStr)
if sreObj:
    print(sreObj.group())
    print(sreObj.groups())
    print(sreObj.groupdict())
    print(sreObj.groupdict()['Text'])

在这里插入图片描述

练习之URL合法性验证

问题描述:
    检查某段给定的文本是不是一个符合须要的URL;

思路:
    1). 检查URL是否以web浏览器广泛采用的通讯协议方案开头: http, https, ftp file
    2). 协议后面紧跟 ://
    3).  协议后面字符任意;
import re
def isUrl(url):
    pattern = re.compile(r'^(http|https|ftp|file)://.+$')
    resObj = re.search(pattern, url)
    if resObj:
        return  True
    return  False


if __name__ == '__main__':
    print(isUrl('file:///tmp'))
    print(isUrl('http://www.baidu.com'))
    print(isUrl('https://www.baidu.com'))
    print(isUrl('ftp://www.baidu.com'))

在这里插入图片描述

北美电话号码的格式化

"""
统一格式为:
            (123) 456-7890
"""
#位置分组的使用
import re
def isPhone(phone):
    pattern = r"\(?([2-9][0-8]\d)\)?[-\.\s]?([2-9]\d{2})[-\.\s]?(\d{4})"
    res = re.search(pattern, phone)
    if res:
        info = res.groups()  # 返回的是元组
        formatPhone = "(%s) %s-%s" %(info[0], info[1], info[2])
        print(formatPhone)
        return True
    return False

print(isPhone('777-777-7777'))
print(isPhone('(777) 777 7890'))
# 命名分组的使用
import re
def isPhone(phone):
    pattern = r"\(?(?P<firstNum>[2-9][0-8]\d)\)?[-\.\s]?(?P<secondNum>[2-9]\d{2})" \
              r"[-\.\s]?(?P<thirdNum>\d{4})"
    res = re.search(pattern, phone)
    if res:
        info = res.groupdict()
        formatPhone = "(%s) %s-%s" %(info['firstNum'],
                                     info['secondNum'], info['thirdNum'])
        print(formatPhone)
        return True
    return False

print(isPhone('777-777-7777'))
print(isPhone('(777) 777 7890'))

在这里插入图片描述

匹配日期

“““
\1: 表明的是必定要与第一个分组的内容保持一致, 不然不匹配;
\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}
“““
import re

date = '2019-10-10'
pattern = r'\d{4}(\-|\/|.)\d{1,2}\1\d{1,2}'

reObj = re.search(pattern, date)
if reObj:
    print(reObj.group())
    print(reObj.groups())

在这里插入图片描述

匹配用户名

字符串是否包含中文 []表示匹配方括号的中任意字符,\u4e00是Unicode中汉字的开始,\u9fa5则是Unicode中汉字的结束
import re
user = '西安邮电大学123'
pattern = r'[\w\-\u4e00-\u9fa5]+'
print(re.findall(pattern, user))

在这里插入图片描述