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))

在這裏插入圖片描述