正則表達式

引言

  文本處理已經成爲計算機常見工做之一, 對文本的搜索、定位、提取的邏輯每每比較複雜, 爲了解決上述問題,產生正則表達式技術html

  正則表達式即文本的高級匹配模式,提供搜索,替代,獲取等功能。本質是由一系列特殊符號和字符構成的自串,這個自串就是正則表達式。python

  正則表達式可以方便地進行檢索和修改等文本操做;靈活多樣;支持語言衆多;正則表達式

正則表達式匹配手段:經過設定有特殊意義的符號,描述符號和字符的重複行爲及位置特徵來表示一類特定規則的字符串sql

import reexpress

re.findall(pattern, string)編程

參數:c#

  • pattern: 以字符串的形式傳入一個正則表達式
  • string:要匹配的目標字符串

返回值:編程語言

  • 獲得一個列表,將目標子串中能用正則表達式匹配的內容放入列表

元字符的使用

普通字符 

匹配規則:每一個普通字符匹配其對應的字符ide

re.findall('ab',"abcdefabcd")
# ['ab', 'ab']

元字符:  |函數

匹配規則:匹配 | 兩側的正則表達式

re.findall('com|cn',"www.baidu.com/www.tmooc.cn")
# ['com', 'cn']

匹配單個字符

元字符: .

匹配規則:匹配除 \n外任意一個字符

re.findall('張.豐',"張三丰,張四豐,張五豐")
# ['張三丰', '張四豐', '張五豐']

匹配字符集

元字符: [字符集]

匹配規則: 匹配字符集中的任意一個字符

表達形式:

  • [abc#!好] 表示 [ ] 中的任意一個字符
  • [0-9], [a-z], [A-Z] 表示區間內的任意一個字符
  • [_#?0-9a-z] 混合書寫,通常區間表達寫在後面
re.findall('[aeiou]',"How are you!")
# ['o', 'a', 'e', 'o', 'u']

匹配字符集反集

元字符: [^字符集]

匹配規則: 匹配除了字符集之外的任意一個字符

re.findall('[^0-9]',"Use 007 port")
# ['U', 's', 'e', ' ', ' ', 'p', 'o', 'r', 't']

匹配開始位置

  • 元字符:  ^
  • 匹配規則: 匹配目標字符串的開頭位置
re.findall('^Jame',"Jame,hello")
# ['Jame']

匹配結束位置

  • 元字符:$
  • 匹配規則:匹配目標字符串的結束位置
re.findall('Jame$',"Hi,Jame")
# ['Jame']
  • 規則技巧:  ^ 和 $必然出如今正則表達式的開頭和結尾處。若是二者同時出現,則中間的部分必須匹配整個目標字符串的所有內容。

匹配字符重複

  • 元字符:  *
  • 匹配規則: 匹配前面的字符出現0次或屢次
re.findall("wo*", "woooo~~w!")  # w後面o出現屢次的狀況和出現0次的狀況
# ['woooo', 'w']
# 大寫字母后面跟小寫之母出現0次或屢次
re.findall("[A-Z][a-z]*", "How ary you? Finf Ha")
# ['How', 'Finf', 'Ha']
  • 元字符: +
  • 匹配規則: 匹配前面的字符出現後面的字符的次數1次或屢次的狀況
# 大寫之母后面跟小寫之母出現1次或屢次
re.findall('[A-Z][a-z]+',"Hello World")
# ['Hello', 'World']
  • 元字符: ?
  • 匹配規則: 匹配前面的字符出現0次或1次
# 匹配整數
re.findall('-?[0-9]+',"Jame,age:18, -26")
# ['18', '-26']
  • 元字符: {n}
  • 匹配規則: 匹配前面的字符出現n次
# 匹配手機號碼
re.findall('1[0-9]{10}',"Jame:13886495728")
# ['13886495728'] 
  • 元字符: {m,n}
  • 匹配規則: 匹配前面的字符出現 [m-n] 次
# 匹配qq號
re.findall('[1-9][0-9]{5,10}',"Baron:1259296994")
# ['1259296994']

匹配任意(非)數字字符

  • 元字符: \d \D
  • 匹配規則: \d 匹配任意數字字符, \D 匹配任意非數字字符
# 匹配端口
re.findall('\d{1,5}',"Mysql: 3306, http:80")
# ['3306', '80'] 

匹配任意(非)普通字符

  • 元字符: \w  \W
  • 匹配規則: \w 匹配普通字符, \W 匹配非普通字符
  • 說明: 普通字符指 數字字母下劃線漢字
re.findall('\w+',"server_port = 8888")
# ['server_port', '8888']

匹配任意(非)空字符

  • 元字符: \s \S
  • 匹配規則: \s 匹配空字符, \S 匹配非空字符
  • 說明:空字符指 空格 \r \n \t \v \f 字符
re.findall('\w+\s+\w+',"hello    world")
# ['hello world']

匹配開頭結尾位置

  • 元字符: \A \Z
  • 匹配規則: \A 表示開頭位置, \Z 表示結尾位置
re.findall("\Ahello","hello world")
# ['hello']
re.findall("world\Z","hello world")
# ['world']

匹配(非)單詞的邊界位置

  • 元字符: \b \B
  • 匹配規則: \b 表示單詞邊界, \B 表示非單詞邊界
  • 說明:單詞邊界指數字字母(漢字)下劃線與其餘字符的交界位置。
re.findall(r'\bis\b',"This is a test.")
# ['is']

總結:

類別 元字符
匹配字符 . [...] [^...] \d \D \w \W \s \S
匹配重複 * + ? {n} {m,n}
匹配位置 ^ $ \A \Z \b \B
其餘 | () \

正則表達式的轉義

1. 若是使用正則表達式匹配特殊字符則須要加 \ 表示轉義。

  特殊字符: . * + ? ^ $ [] () {} | \

# 匹配特殊字符 . 時使用 \. 表示自己含義
re.findall('-?\d+\.?\d*',"123,-123,1.23,-1.23")
# ['123', '-123', '1.23', '-1.23']

2. 在編程語言中,常使用原生字符串書寫正則表達式避免多重轉義的麻煩。

  python字符串  --> 正則 --> 目標字符串

  "\\$\\d+"  解析爲  \$\d+ 匹配 "$100"

  "\\$\\d+"  等同於  r"\$\d+"

貪婪模式和非貪婪模式

貪婪模式: 默認狀況下,匹配重複的元字符老是儘量多的向後匹配內容。好比: * + ? {m,n}

非貪婪模式(懶惰模式): 讓匹配重複的元字符儘量少的向後匹配內容。

貪婪模式轉換爲非貪婪模式: 在匹配重複元字符後加  '?'  號便可

    * ---> *?  ;         + ---> +?  ;       ? ---> ??  {m,n} ---> {m,n}?

re.findall("ab*", "abbbbb") # ['abbbbb']
re.findall("ab*?", "abbbbb")  # ['a']

re.findall("ab+", "abbbbb") # ['abbbbb']
re.findall("ab+?", "abbbbb") # ['ab']

練習"

# 把數字匹配出來
re.findall("[^ ]+", "12 -36 28 1.34 -3.8")
# ['12', '-36', '28', '1.34', '-3.8']

re.findall("-?\d+\.?\d*", "12 -36 28 1.34 -3.8")
# ['12', '-36', '28', '1.34', '-3.8']
# 匹配一個.com郵箱格式字符串
print(re.findall(r"\w+@\w+", "lvze@163.com"))
# 匹配一個密碼 8-12位數字字母下劃線構成
print(re.findall(r"\w{8,12}", "Tedu023256"))
# 匹配一個數字 正數,負數,整數,小數,分數1/2,百分數45%
print(re.findall(r"-?\d+/?\.?\d*%?", "12 -3 3.5 5.45 42% 1/3"))
# 匹配一段文字中以大寫字母開頭的單詞,注意文字中可能有ipython(不算)H-base(算),單詞可能有大寫字母小寫之母 -_
print(re.findall(r"\b[A-Z][-_a-zA-Z]*", "Hello ipython H-base BSD"))

分組

  在正則表達式中, 以 () 創建正則表達式的內部分組, 匹配括號內的表達式,分組的做用是在完整的模式中定義子模型,將每一個圓括號中子模式專門匹配出來

  • 能夠被做爲總體操做, 改變元字符的操做對象
# 改變 +號 重複的對象
re.search(r'(ab)+',"ababababab").group()
#  'ababababab'
# 改變 |號 操做對象
re.search(r'(王|李)\w{1,3}',"王者榮耀").group()
# '王者榮耀'
  •  能夠經過編程語言某些接口獲取匹配內容中,子組對應的內容部分 
# 獲取url協議類型
re.search(r'(https|http|ftp|file)://\S+',"https://www.baidu.com").group(1)
# 'https'

 先匹配外部正則,再進一步匹配括號中的正則

import re

s = 'A B C D'
p1 = re.compile('\w+\s+\w+')
print(p1.findall(s))        # # ['A B','C D']

p2 = re.compile('(\w+)\s+\w+')
print(p2.findall(s))        # # ['A','C']

p3 = re.compile('(\w+)\s+(\w+)')
print(p3.findall(s))        # # [('A','B'),('C','D')]
import re

html = '''<div class="animal">
    <p class="name">
        <a title="Tiger"></a>
    </p>
    <p class="content">
        Two tigers two tigers run fast
    </p>
</div>

<div class="animal">
    <p class="name">
        <a title="Rabbit"></a>
    </p>

    <p class="content">
        Small white rabbit white and white
    </p>
</div>'''

pattern = re.compile(
    '<div class="animal">.*?title="(.*?)".*?'
    'class="content">(.*?)</p>',
    re.S)
r_list = pattern.findall(html)
print(r_list)
View Code

分組總結

  1. 在網頁中,想要什麼內容,就加 ( )
  2. 先按總體正則匹配,而後再提取分組()中的內容  
  3. 若是有2個及以上分組(),則結果中以元組形式顯示 [(),(),()]

捕獲組

能夠給正則表達式的子組起一個名字,表達該子組的意義。這種有名稱的子組即爲捕獲組。

格式: (?P<name>pattern)

# 給子組命名爲 "pig"
re.search(r'(?P<pig>ab)+',"ababababab").group('pig')
# 'ab'

注意事項

  • 一個正則表達式中能夠包含多個子組
  • 子組能夠嵌套,可是不要重疊或者嵌套結構複雜
  • 子組序列號通常從外到內,從左到右計數

Python re模塊

re.match函數

re.match(pattern, string, flags=0)

參數:

  • pattern 正則
  • string 目標字符串
  • flags 標誌位, 用於控制表達式的匹配方式,如:是否區分大小寫...

返回值:匹配內容match 對象

re.match嘗試從字符串的起始位置匹配一個模型,若是不是起始位置匹配成功的話,match()就返回none.

import re
print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配, (0, 3)
print(re.match('com', 'www.runoob.com'))         # 不在起始位置匹配, None

咱們可使用group()或groups()匹配對象函數來匹配表達式. 

  • group(num=0)  匹配的整個表達式的字符串,group() 能夠一次輸入多個組號,在這種狀況下它將返回一個包含那些組所對應值的元組。 
  • groups()                返回一個包含全部小組字符串的元組,從 1 到 所含的小組號。
import re

line = "Cats are smarter than dogs"
# .* 表示任意匹配除換行符(\n、\r)以外的任何單個或多個字符
matchObj = re.match(r'(.*) are (.*?) .*', line)

print(matchObj.group())     # Cats are smarter than dogs
print(matchObj.group(1))    # Cats
print(matchObj.group(2))    # smarter

m = re.match(r"[A-Z]\w*", "Hello World")
print(m.group())    # Hello

re.search函數

re.search 掃描整個字符串並返回第一個成功的匹配。

re.search(pattern, string, flags=0)

參數:

  • pattern 正則
  • string 目標字符串
  • flags 標誌位, 用於控制表達式的匹配方式,如:是否區分大小寫...

返回值: 匹配目標字符串第一個符合內容 的對象

咱們可使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。同re.match

import re

line = "Cats are smarter than dogs"

# .* 表示任意匹配除換行符(\n、\r)以外的任何單個或多個字符
searchObj = re.search(r'(.*) are (.*?) .*', line)
print(searchObj)        # <_sre.SRE_Match object; span=(0, 26), match='Cats are smarter than dogs'>
print(searchObj.group())        # Cats are smarter than dogs
print(searchObj.group(1))       # Cats
print(searchObj.group(2))       # smarter

# 匹配第一處
m = re.search(r"[A-Z]\w*", " Hello World")
print(m.group())    # Hello

match和search區別: re.match只匹配字符串的開始,若是字符串開始不符合正則表達式,則匹配失敗,函數返回None;而re.search匹配整個字符串,直到找到一個匹配。

re.sub()替換函數

re.sub(pattern,replace,string,max,flags = 0)

使用一個字符串替換正則表達式匹配到的內容

參數:

  • pattern 正則表達式
  • replace 替換的字符串
  • string 目標字符串
  • max 最多替換幾處, 默認替換所有
  • flags 功能標誌位,擴展正則表達式的匹配

返回值: 替換後的字符串

import re

phone = "2004-959-559 # 這是一個電話號碼"

# 刪除註釋
num_1 = re.sub(r'#.*$', "", phone)    # 2004-959-559   

# 移除非數字的內容
num_2 = re.sub(r'\D', "", phone)      # 2004959559

# 替換匹配到的內容
s = re.subn(r'\s+', '#', "This is a test", 2)  # ('This#is#a test', 2)

compile 函數

regex = compile(pattern,flags = 0)

參數:

  • pattern 正則表達式
  • flags 功能標誌位,擴展正則表達式的匹配

返回值:  正則表達式對象

compile 函數用於編譯正則表達式,生成一個正則表達式( Pattern )對象,供 match() 和 search() 這兩個函數使用。

import re
pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)   # re.I 表示忽略大小寫
m = pattern.match('Hello World Wide Web')
print(m)        # 匹配成功,返回一個 Match 對象 # <_sre.SRE_Match object; span=(0, 11), match='Hello World'>
print(m.group(0))       # 返回匹配成功的整個子串,Hello World
print(m.group(1))       # 返回第一個分組匹配成功的子串,Hello
print(m.groups())       # 等價於 (m.group(1), m.group(2), ...)  ('Hello', 'World')
print(m.group(3))       # 不存在第三個分組 報錯!!!
print(m.span(0))        # 返回匹配成功的整個子串的索引,(0, 11)

re.findall()函數 

re.findall(pattern,string,flags = 0)

參數:

  • pattern 正則表達式
  • string 目標字符串
  • flags 功能標誌位,擴展正則表達式的匹配

返回值: 在字符串中找到正則表達式所匹配的全部子串,並返回一個列表,若是沒有找到匹配的,則返回空列表。

注意: match 和 search 是匹配一次 findall 匹配全部。

import re

# 目標字符串
s = "Alex:1994,Sunny:1993"
pattern = r"(\w+):(\d+)"

# re模塊調用findall
l = re.findall(pattern, s)
print(l)        # [('Alex', '1994'), ('Sunny', '1993')]

 

re.finditer(pattern,string,flags = 0)  根據正則表達式匹配目標字符串內容

參數:

  • pattern 正則表達式
  • string 目標字符串
  • flags 功能標誌位,擴展正則表達式的匹配

返回值: 匹配結果的迭代器, 返回的對象要經過.group()取值

import re

s = "2019年,建國70年"
pattern = r'\d+'

# 返回迭代器
it = re.finditer(pattern,s)
for i in it:
  print(i)  # 獲取match對象對應內容
  # <_sre.SRE_Match object; span=(0, 4), match='2019'>
  # <_sre.SRE_Match object; span=(0, 4), match='70'>

re.fullmatch(pattern,string,flags=0)  

參數:

  • pattern 正則
  • string 目標字符串

返回值:徹底匹配某個目標字符串 object

# 徹底匹配
print(re.fullmatch("[,\w]+", s).group())    # 2019年,建國70年

re.split(pattern,string,flags = 0)  使用正則表達式匹配內容,切割目標字符串

參數:

  • pattern 正則表達式
  • string 目標字符串
  • flags 功能標誌位,擴展正則表達式的匹配

返回值: 切割後的內容列表

s = "Alex:1994,Sunny:1993"
# 按照匹配內容切割字符串
l = re.split(r'[:,]', s)
print(l)        # ['Alex', '1994', 'Sunny', '1993']
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息