溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

怎么理解并掌握python正則表達(dá)式和re模塊

發(fā)布時(shí)間:2021-11-03 17:28:21 來(lái)源:億速云 閱讀:105 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“怎么理解并掌握python正則表達(dá)式和re模塊”,在日常操作中,相信很多人在怎么理解并掌握python正則表達(dá)式和re模塊問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么理解并掌握python正則表達(dá)式和re模塊”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

  1.正則表達(dá)式

  正則表達(dá)式,又稱(chēng)規(guī)則表達(dá)式。(英語(yǔ):Regular Expression,在代碼中常簡(jiǎn)寫(xiě)為regex、regexp或RE),計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式通常被用來(lái)檢索、替換那些符合某個(gè)模式(規(guī)則)的文本。

  下面是正則表達(dá)式常見(jiàn)的使用場(chǎng)景:

  檢查字符串的合法性

  驗(yàn)證用戶(hù)名 (a-z,0-9,不能全是數(shù)字,不能全是字母)

  驗(yàn)證郵箱格式 (xxx@qq.com)

  驗(yàn)證電話(huà)號(hào)碼 (11位數(shù)字)

  驗(yàn)證身份證 (18位 )

  驗(yàn)證號(hào)碼格式(5-12純數(shù)字,第一位不能為0);

  提取字符串中信息

  提取一條短信中數(shù)字;

  提取文件名的后綴;

  采集器(網(wǎng)絡(luò)爬蟲(chóng))

  替換字符串

  替換字符串中的非法字符;

  對(duì)電話(huà)號(hào)碼進(jìn)行屏蔽;(1852****0102)

  替換占位符 “hello {{name}} ” hello 王老二 (模板框架)

  分割字符串

  將一個(gè)字符串按照指定的規(guī)則進(jìn)行分割;

  通俗地說(shuō),正則的功能是檢索特定形式的字符串,對(duì)象是字符串。

  1.1 元字符

  使用元字符匹配單個(gè)字符

  字符  功能

  .  匹配任意1個(gè)字符(除了\n)

  [ ]  匹配[ ]中列舉的字符

  \d  匹配數(shù)字,即0-9

  \D  匹配非數(shù)字,即不是數(shù)字

  \s  匹配空白,即 空格,tab鍵

  \S  匹配非空白

  \w  匹配單詞字符,即a-z、A-Z、0-9、_

  \W  匹配非單詞字符

  *  匹配前一個(gè)字符出現(xiàn)0次或者無(wú)限次,即可有可無(wú)

  +  匹配前一個(gè)字符出現(xiàn)1次或者無(wú)限次,即至少有1次

  import re

  text = '''

  這是用來(lái)匹配的字符串

  from:1427319758@qq.com

  tel:88888888

  '''

  針對(duì)上述字符串進(jìn)行元字符的正則匹配演示

  使用點(diǎn).匹配任意字符

  res = re.findall('.',text)

  print(res)

  運(yùn)行結(jié)果(注意返回的是列表):

  ['這', '是', '用', '來(lái)', '匹', '配', '的', '字', '符', '串', 'f', 'r', 'o', 'm', ':', '1', '4', '2', '7', '3', '1', '9', '7', '5', '8', '@', 'q', 'q', '.', 'c', 'o', 'm', 't', 'e', 'l', ':', '8', '8', '8', '8', '8', '8', '8', '8']

  \d匹配數(shù)字

  res = re.findall('\d',text)

  print(res)

  運(yùn)行結(jié)果:

  ['1', '4', '2', '7', '3', '1', '9', '7', '5', '8', '8', '8', '8', '8', '8', '8', '8', '8']

  + * 匹配多個(gè)字符

  res = re.findall('\d+',text)

  res_1 = re.findall('\d*',text)

  print(res,res_1)

  運(yùn)行結(jié)果:

  ['1427319758', '88888888']

  ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '1427319758', '', '', '', '', '', '', '', '', '', '', '', '', '88888888', '', '']

  *匹配前一字符可以是0次,因此\d*會(huì)匹配每個(gè)不是數(shù)字的字符,即為空。\d+等同\d\d*

  [](字符集)

  人為規(guī)定只能匹配出現(xiàn)在字符集中的字符,如要找尋字符串中的qq號(hào),qq號(hào)不能以0開(kāi)頭,且位數(shù)是5~12

  可用[1-9]\d{4,11}來(lái)限制

  郵箱可能出現(xiàn)為字符串,可用[1-9a-zA-Z]\w+[@]\w+[.][a-zA-z]+可以匹配出任意常規(guī)格式的郵箱

  res = re.findall('[1-9a-zA-Z]\w+[@]\w+[.][a-zA-z]+','''

  1427319758@163.com開(kāi)會(huì)就

  1427319758@edu.cn是否

  1427319758@xx.mail 阿薩德

  asdfbglsafhlf上單發(fā)順豐打打分

  ''')

  print(res)

  運(yùn)行結(jié)果:

  ['1427319758@163.com', '1427319758@edu.cn', '1427319758@xx.mail']

  使用.*匹配任意多個(gè)字符

  res = re.findall('.*',text)

  print(res)

  運(yùn)行結(jié)果:

  ['', '這是用來(lái)匹配的字符串', '', 'from:1427319758@qq.com', '', 'tel:88888888', '', '']

  由于re.findall()函數(shù)默認(rèn)遇到換行符 '\n’會(huì)終止當(dāng)前的匹配,即不匹配換行符,每一行單獨(dú)匹配,因此會(huì)出現(xiàn)空元素。

  1.2 數(shù)量詞

  使用數(shù)量詞匹配多個(gè)字符

  字符  功能

  {m}  匹配前一個(gè)字符出現(xiàn)m次

  {m,n}  匹配前一個(gè)字符出現(xiàn)從m到n次

  限制匹配字符出現(xiàn)的次數(shù)

  res = re.findall('[1-9]\d{4,11}',text)

  res_1 = re.findall('([1-9]\d{4,11})@',text)

  print(res,res_1)

  運(yùn)行結(jié)果:

  ['1427319758', '88888888'] ['1427319758']

  第一種方式匹配了同樣滿(mǎn)足規(guī)則的手機(jī)號(hào),第二種方式是考慮到qq號(hào)隱藏在郵箱地址里,所以在后面加了@來(lái)限制匹配的區(qū)域,即只匹配@前的第1位非0的5-12位純數(shù)字。

  1.3 精確匹配與泛匹配

  泛匹配

  泛匹配是匹配包括特征字符在內(nèi)的所有的東西

  res = re.findall('Hello.*like','Hello world! I like python!')

  print(res)

  運(yùn)行結(jié)果:

  ['Hello world! I like']

  精確匹配

  精確匹配是匹配括號(hào)里面的東西

  res_1 = re.findall('Hello(.*)like','Hello world! I like python!')

  print(res_1)

  運(yùn)行結(jié)果:

  [' world! I ']

  我想要Hello和like之間的字符,泛匹配的結(jié)果會(huì)包含首尾的特征字符Hello和like;而精確匹配只會(huì)得到特征字符之間的字符串。

  1.4 貪婪匹配與非貪婪匹配

  Python里數(shù)量詞默認(rèn)是貪婪的(在少數(shù)語(yǔ)言里也可能是默認(rèn)非貪婪),總是嘗試匹配盡可能多的字符;

  非貪婪則相反,總是嘗試匹配盡可能少的字符。

  在"*","?","+","{m,n}"后面加上?,使貪婪變成非貪婪。

  res = re.findall('Hello(.*)like','Hello world! I like python! I like you!')

  res_1 = re.findall('Hello(.*?)like','Hello world! I like python! I like you!')

  print(res,res_1)

  運(yùn)行結(jié)果:

  [' world! I like python! I ']

  [' world! I ']

  res返回的是貪婪匹配,它會(huì)在找到Hello后,匹配盡可能多的字符,然后在最后一個(gè)like停下;

  res_1返回的是非貪婪匹配,它在找到Hello后,只匹配第一個(gè)like前的字符。

  2. re模塊

  一直以來(lái)我們都是使用 re.search() 函數(shù),其實(shí)在正則表達(dá)式模塊中還有一些函數(shù)可以很方便的對(duì)字符串進(jìn)行操作。re模塊的使用可以分為兩種:第一種是對(duì)象式的方式,第二種是函數(shù)式的方式。

  2.1 re.match

  match() 用于查找字符串的頭部(也可以指定起始位置),它是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回,而不是查找所有匹配的結(jié)果。它的一般使用形式如下:

  match(pattern, string[, flag])

  其中,pattern是正則表達(dá)式規(guī)則字符串,string 是待匹配的字符串,flag 是可選參數(shù)。

  當(dāng)匹配成功時(shí),返回一個(gè) Match 對(duì)象,如果沒(méi)有匹配上,則返回 None。

  import re

  pattern = 'Python'

  string = 'dsgfaPythonahsdgjasghPythonasdjajsk'

  result = re.match(pattern,string)

  result_1 = re.match(pattern,string[5:])

  print(result,result_1)

  運(yùn)行結(jié)果:

  None

  <_sre.SRE_Match object; span=(0, 6), match='Python'>

  2.2 re.search

  search() 用于查找字符串的任何位置,它也是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回,而不是查找所有匹配的結(jié)果,它的一般使用形式如下:

  search(pattern, string[, flag])

  當(dāng)匹配成功時(shí),返回一個(gè) Match 對(duì)象,如果沒(méi)有匹配上,則返回 None。

  ret = re.search('\d+', "python = 9999, c = 7890, c++ = 12345")

  print(ret.group())

  運(yùn)行結(jié)果:

  9999

  2.3 re.findall 劃重點(diǎn)!

  上面的 match 和 search 方法都是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回。然而,在大多數(shù)時(shí)候,我們需要搜索整個(gè)字符串,獲得所有匹配的結(jié)果。findall() 的使用形式如下:

  findall(pattern, string[, flag])

  findall() 以列表形式返回全部能匹配的子串,如果沒(méi)有匹配,則返回一個(gè)空列表。

  ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")

  print(ret)

  運(yùn)行結(jié)果:

  ['9999', '7890', '12345']

  2.4 re.split

  split()按照能夠匹配的子串將字符串分割后返回列表,它的使用形式如下:

  split(pattern, string[, maxsplit, flags])

  其中,maxsplit 用于指定最大分割次數(shù),不指定將全部分割。

  '''

  split():

  分割字符串 去掉了匹配到的字符串

  結(jié)果是列表形式

  maxsplit: 默認(rèn)是0 表示全部切割

  1 代表切割一次

  2 代表切割兩次

  '''

  pattern = '\d+'

  string = 'Pythonasdkjasd464654adhuiaghsdk564654akjsdhkashdkja'

  result = re.split(pattern,string,2)

  print(result)

  運(yùn)行結(jié)果:

  ['Pythonasdkjasd', 'adhuiaghsdk', 'akjsdhkashdkja']

  實(shí)際上就是面向字符串操作的string.split的升級(jí)版

  2.5 re.sub

  sub()用于替換,使用形式如下:

  sub(pattern, repl, string[, count, flags])

  第一個(gè)參數(shù)為對(duì)應(yīng)的正則表達(dá)式,第二個(gè)參數(shù)為要替換成的字符串,第三個(gè)參數(shù)為源字符串,第四個(gè)參數(shù)為可選項(xiàng),代表最多替換的次數(shù),如果忽略不寫(xiě),則會(huì)將符合模式的結(jié)果全部替換。

  pattern = 'Java'

  repl = '********'

  string = 'kjasdJavaadhuiaghsdkJavaakjsd'

  result = re.sub(pattern,repl,string,1)

  print(result)

  運(yùn)行結(jié)果:

  kjasd********adhuiaghsdkJavaakjsd

  string.replace的升級(jí)版

  參數(shù)flags

  方法1:

  ret = re.sub("\d+", '18', "age = 12")

  print(ret)

  運(yùn)行結(jié)果:

  age = 18

  方法2 用函數(shù):

  re.sub()的本質(zhì)是在字符串中檢索符合pattern格式的子串,然后把子串當(dāng)做參數(shù)輸入repl中,默認(rèn)的repl功能可以看成是函數(shù),即不論我輸入的子串是什么樣的,輸出都用repl參數(shù)代替,此處repl無(wú)法跟子串產(chǎn)生關(guān)系

  def replace(string,repl):

  return repl

  如果我們要讓輸出的repl和子串產(chǎn)生關(guān)系,如將字符串中的電話(huà)號(hào)碼15654862043輸出成1565****043,僅僅通過(guò)設(shè)定一個(gè)repl字符串是不能實(shí)現(xiàn)的,就需要在repl處傳入一個(gè)函數(shù)。

  import re

  text = '''

  15654561654

  13905641750

  15646575635

  18976534547

  '''

  def replace(string):

  string = string.group()

  repl = string[0:4] + '****' + string[-4:-1]

  return repl

  ret = re.sub("\d+", repl = replace, string = text)

  print(ret)

  運(yùn)行結(jié)果:

  1565****165

  1390****175

  1564****563

  1897****454

  2.6 re.compile

  使用 compile() 函數(shù)將正則表達(dá)式的字符串形式編譯為一個(gè) Pattern 對(duì)象。通過(guò)該對(duì)象提供的一系列方法對(duì)文本進(jìn)行匹配查找,獲得匹配結(jié)果(Match對(duì)象)。編譯可以實(shí)現(xiàn)更高效的匹配查找等。

  compile()函數(shù)

  compile() 函數(shù)用于編譯正則表達(dá)式,生成一個(gè) Pattern 對(duì)象,它的一般使用形式如下:

  import re

  # 將正則表達(dá)式編譯成 Pattern 對(duì)象

  pattern_1 = re.compile('\d+', re.S)

  pattern_2 = re.compile('\D+', re.l)

  pattern_3 = re.compile('\w+', re.S)

  之前定義pattern都是不包括flags參數(shù)的,因此不用re.compile,僅用賦值語(yǔ)句讓pattern = ‘\d+’也能實(shí)現(xiàn),compile函數(shù)的優(yōu)點(diǎn)在于:1.可以包含flags參數(shù);2.形成模塊,便于后續(xù)復(fù)用

  results1 = re.findall(pattern_1, '540775360@qq.com')

  results2 = re.findall(pattern_2, "python = 9999, c = 7890, c++ = 12345")

  results3 = re.findall(pattern_3, "python = 997")

  print(results1, results2, results3)

  2.7 原生字符串

  >>> mm = "c:\\a\\b\\c"

  >>> mm

  'c:\\a\\b\\c'

  >>> print(mm)

  c:\a\b\c

  >>> re.match("c:\\\\",mm).group()

  'c:\\'

  >>> ret = re.match("c:\\\\",mm).group()

  >>> print(ret)

  c:\

  >>> ret = re.match("c:\\\\a",mm).group()

  >>> print(ret)

  c:\a

  >>> ret = re.match(r"c:\\a",mm).group()

  >>> print(ret)

  c:\a

  >>> ret = re.match(r"c:\a",mm).group()

  Traceback (most recent call last):

  File "", line 1, in

  AttributeError: 'NoneType' object has no attribute 'group'

  >>>鄭州做流產(chǎn)多少錢(qián) http://www.kdwtrl.com/

  Python中字符串前面加上 r 表示原生字符串,

  與大多數(shù)編程語(yǔ)言相同,正則表達(dá)式里使用"\"作為轉(zhuǎn)義字符,這就可能造成反斜杠困擾。假如你需要匹配文本中的字符"\\",那么使用編程語(yǔ)言表示的正則表達(dá)式里將需要4個(gè)反斜杠"\":前兩個(gè)和后兩個(gè)分別用于在編程語(yǔ)言里轉(zhuǎn)義成反斜杠,轉(zhuǎn)換成兩個(gè)反斜杠后再在正則表達(dá)式里轉(zhuǎn)義成一個(gè)反斜杠。

  Python里的原生字符串很好地解決了這個(gè)問(wèn)題,有了原生字符串,你再也不用擔(dān)心是不是漏寫(xiě)了反斜杠,寫(xiě)出來(lái)的表達(dá)式也更直觀(guān)。

  >>> ret = re.match(r"c:\\a",mm).group()

  >>> print(ret)

  c:\a

  2.8 匹配開(kāi)頭結(jié)尾

  字符  功能

  ^  匹配字符串開(kāi)頭

  $  匹配字符串結(jié)尾

  末尾匹配

  需求:匹配163.com的郵箱地址

  #coding=utf-8

  import re

  email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]

  for email in email_list:

  ret = re.match("[\w]{4,20}@163\.com", email)

  if ret:

  print("%s 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:%s" % (email, ret.group()))

  else:

  print("%s 不符合要求" % email)

  運(yùn)行結(jié)果:

  xiaoWang@163.com 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com

  xiaoWang@163.comheihei 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com

  .com.xiaowang@qq.com 不符合要求

  完善后

  email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]

  for email in email_list:

  ret = re.match("[\w]{4,20}@163\.com$", email)

  if ret:

  print("%s 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:%s" % (email, ret.group()))

  else:

  print("%s 不符合要求" % email)

  運(yùn)行結(jié)果:

  xiaoWang@163.com 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com

  xiaoWang@163.comheihei 不符合要求

  .com.xiaowang@qq.com 不符合要求

  這個(gè)例子只用于展示,用來(lái)匹配郵箱是沒(méi)有意義的。因?yàn)樗ヅ洳怀瞿┪膊皇莄om但包含了郵箱信息的多行字符串,如

  '''

  xiaoWang@163.com

  xiaoKang@163.com

  以上就是郵箱

  '''

  萬(wàn)能正則

  (.*?) 匹配除了換行以外的任意字符串。無(wú)論長(zhǎng)短,最多匹配一次,非貪婪匹配。

  這個(gè)正則表達(dá)式可以解決你想要提取的大部分?jǐn)?shù)據(jù),在寫(xiě)正則表達(dá)式的時(shí)候可以首先嘗試這個(gè)組合,也許能達(dá)到事半功倍的效果。并且常常結(jié)合re.findall()函數(shù)。

  2.9 案例:抓取電影天堂數(shù)據(jù)

  '''

  電影天堂思路:

  1. 進(jìn)入最新的電影更多 --> 更多的第一頁(yè)

  2. 翻頁(yè) https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html

  1. > 提取每一頁(yè)的數(shù)據(jù)電影的詳情頁(yè)網(wǎng)址

  2. > 發(fā)送請(qǐng)求 得到響應(yīng)

  3. > 正則提取鏈接

  4. > 保存數(shù)據(jù)(文件)

  抓取之前盡量熟悉網(wǎng)頁(yè)的布局和結(jié)構(gòu)!! 熟悉網(wǎng)址的關(guān)系, 經(jīng)常查找網(wǎng)頁(yè)源碼中的數(shù)據(jù)(Ctrl+F).

  '''

  import re

  import requests

  for page in range(1, 5):

  url_list = f'https://www.dytt8.net/html/gndy/dyzz/list_23_{page}.html'

  # 找到詳情頁(yè)的網(wǎng)址 先進(jìn)入 列表頁(yè)

  r_list = requests.get(url_list)

  # 指定編碼

  r_list.encoding = 'gb2312'

  # 提取詳情頁(yè)的網(wǎng)址 返回列表

  url_detail = re.findall('', r_list.text)

  for u in url_detail:

  url = 'https://www.dytt8.net' + u

  # print(url)

  # 再次發(fā)請(qǐng)求 得到詳情頁(yè)的響應(yīng)

  response = requests.get(url)

  # 也會(huì)亂碼

  response.encoding = 'gb2312'

  # 提取數(shù)據(jù)

  result = re.findall('.*?', response.text)[0:]

  print(result)

  try:

  with open('dytt.txt', 'a', encoding='utf-8') as fp:

  # write 只能字符串 和 二進(jìn)制的 不能寫(xiě)字典 列表 等

  fp.write(result[0]+'\n')

  except:

  print('沒(méi)有提取到數(shù)據(jù)!!')

  '''

  歌曲下載:

  可見(jiàn)即可爬 電影(VIP) 歌曲

  思路:

  1. 抓包 找到翻頁(yè) http://www.htqyy.com/genre/musicList/3?pageIndex=6&pageSize=20&order=hot

  2. 進(jìn)入上面的網(wǎng)址 提取歌曲id

  3. 下載歌曲 http://f2.htqyy.com/play7/{id}/mp3/1

  '''

  import re

  import requests

  for page in range(1, 3): # 1, 2

  # 翻頁(yè)的

  url_song = f'http://www.htqyy.com/genre/musicList/3?pageIndex={page}&pageSize=20&order=hot'

  # 發(fā)送請(qǐng)求得到響應(yīng) 提取響應(yīng)中的歌曲ID

  response_song = requests.get(url_song)

  # 提取ID 返回列表

  id_songs = re.findall('value="(\d+)">

  # 遍歷歌曲的id 然后下載

  for ids in id_songs:

  song_url = 'http://f2.htqyy.com/play7/{}/mp3/1'.format(ids)

  try:

  # 請(qǐng)求歌曲的網(wǎng)址 然后得到響應(yīng)

  response = requests.get(song_url, timeout=5)

  # 保存歌曲

  with open(f'{ids}.mp3', 'wb') as fp:

  fp.write(response.content)

  except:

  print(f'這個(gè)歌曲{ids}出錯(cuò)')

到此,關(guān)于“怎么理解并掌握python正則表達(dá)式和re模塊”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI