【NLP】正則表達式

1. 爲什麼使用正則表達式

正則表達式是 處理字符串的強大工具,擁有獨特的語法和獨立的處理引擎。

典型的搜索和替換操作要求提供與預期的搜索結果匹配的確切文本。雖然這種技術對於對靜態文本執行簡單搜索和替換任務可能已經足夠了,但它缺乏靈活性,若採用這種方法搜索動態文本,即使不是不可能,至少也會變得很困難。
通過使用正則表達式,可以:

  • 測試字符串內的模式。
    例如,可以測試輸入字符串,以查看字符串內是否出現電話號碼模式或信用卡號碼模式。這稱爲數據驗證。
  • 替換文本。
    可以使用正則表達式來識別文檔中的特定文本,完全刪除該文本或者用其他文本替換它。
  • 基於模式匹配從字符串中提取子字符串。
    可以查找文檔內或輸入域內特定的文本。
    例如,可能需要搜索整個網站,刪除過時的材料,以及替換某些 HTML 格式標記。在這種情況下,可以使用正則表達式來確定在每個文件中是否出現該材料或該 HTML 格式標記。此過程將受影響的文件列表縮小到包含需要刪除或更改的材料的那些文件。然後可以使用正則表達式來刪除過時的材料。最後,可以使用正則表達式來搜索和替換標記。

正則表達式是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱爲"元字符")。使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串。
效率上可能不如str自帶的方法,但匹配功能實在強大太多。另外,正則表達式不是Python獨有的,如果已經在其他語言裏使用過正則表達式,這裏的說明只需要簡單看一看就可以上手啦。

1.語法

這裏有一份正則表達式小抄,即我們在寫正則表達式時可以參考以下圖表內容。
字符

模式 描述
. 匹配任意字符,除了\n。當re.DOTALL標記被指定時,就可以匹配含換行符的任意字符。
[…] 字符集。 字符集中的字符可以逐個列出,也可以給出範圍,例如[abc]或[a-c]
[^…] 匹配不在[ ]中的字符,例如[^abc] 匹配除了a,b,c之外的字符。

預定義字符集(也可以寫在字符集[…]中)

模式 描述
\d 匹配任意數字====[0-9]
\D 匹配任意非數字====[^\d]
\s 匹配任意空白字符,包括空格、製表符、換頁符等等。====[\t\n\r\f]
\S 匹配任意非空字符====[^\s]
\w 匹配字母數字及下劃線====[A-Za-z0-9_]
\W 匹配非字母數字及下劃線====[^\w]

數量詞 用在字符或者(…)之後

模式 描述
* 匹配0個或多個的表達式
+ 匹配1個或多個的表達式。
匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式
{m} 精確匹配 m個前面表達式。例如, o{2} 不能匹配 “Bob” 中的 “o”,但是能匹配 “food” 中的兩個 o。
{m,} 匹配 m 個前面表達式。例如, o{2,} 不能匹配"Bob"中的"o",但能匹配 "foooood"中的所有 o。“o{1,}” 等價於 “o+”。“o{0,}” 則等價於 “o*”。
{m,n} 匹配m到n次由前面的正則表達式定義的片段,貪婪方式

邊界匹配

模式 描述
^ 匹配字符串的開頭。在多行模式中,匹配每一行的開頭。
$ 匹配字符串的末尾。在多行模式中,匹配每一行的末尾。
\A 僅匹配字符串開始
\Z 僅匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。
\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非單詞邊界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。

【補充】
1.數量詞的貪婪匹配和非貪婪匹配
Python裏數量詞默認是貪婪的(在少數語言裏也可能是默認非貪婪),總是嘗試匹配儘可能多的字符;非貪婪的則相反,總是嘗試匹配儘可能少的字符。例如:正則表達式"ab*“如果用於查找"abbbc”,將找到"abbb"。而如果使用非貪婪的數量詞"ab*?",將找到"a"。即貪婪爲 .* ,非貪婪爲 .* ?。

2.驗證工具
正則表達式在線驗證工具之一是 http://regexr.com/

3.正則表達式在線練習
https://regexr.com/
https://alf.nu/RegexGolf

3.python的re模塊

re = regular experssion
re 模塊使 Python 語言擁有全部的正則表達式功能。
compile 函數根據一個模式字符串和可選的標誌參數生成一個正則表達式對象。該對象擁有一系列方法用於正則表達式匹配和替換。
re 模塊也提供了與這些方法功能完全一致的函數,這些函數使用一個模式字符串做爲它們的第一個參數。
本章節主要介紹Python中常用的正則表達式處理函數。

3.1 re.match函數

match嘗試從字符串的起始位置開始匹配;

  • 如果起始位置沒有匹配成功, 返回None;
  • 如果起始位置匹配成功, 返回一個對象, 通過group方法獲取匹配的內容;

函數語法:

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

函數參數說明:

參數 描述
pattern 匹配的正則表達式
string 要匹配的字符串
flags 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等

正則表達式修飾符-可選標誌flags:

修飾符 描述
re.I 使匹配對大小寫不敏感
re.L 做本地化識別(locale-aware)匹配
re.M 多行匹配,影響 ^ 和 $
re.S 使 . 匹配包括換行在內的所有字符
re.U 根據Unicode字符集解析字符。這個標誌影響 \w, \W, \b, \B.

匹配成功re.match方法返回一個匹配的對象,否則返回None。
我們可以使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。

import re
aObj = re.match(r'we', 'we are Chinese')
print(aObj)
print(aObj.group())

執行效果如下:
在這裏插入圖片描述

匹配對象方法 描述
group(num=0) 匹配的整個表達式的字符串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應值的元組。
groups( ) 返回一個包含所有小組字符串的元組,從 1 到 所含的小組號。

group( ) 返回被 re 匹配的字符串。

  • start() 返回匹配開始的位置
  • end() 返回匹配結束的位置
  • span() 返回一個元組包含匹配 (開始,結束) 的位置
import re
print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.match('www', 'www.runoob.com').start())  
print(re.match('www', 'www.runoob.com').end())  
print(re.match('com', 'www.runoob.com'))         # 不在起始位置匹配

執行效果如下:
在這裏插入圖片描述

import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
#標誌位的設置,在前面表格flags
if matchObj:
    print("matchObj.group() : ", matchObj.group())
    print('matchObj.group(1) :', matchObj.group(1))
    print('matchObj.group(2) :' , matchObj.group(2))
    print("matchObj.group(1,2) : ", matchObj.group(1,2))
    print("matchObj.groups() : ", matchObj.groups())
else:
    print('no match!')

執行效果如下:

在這裏插入圖片描述

3.2 re.search函數

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

函數語法:

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

函數參數說明:

參數 描述
pattern 匹配的正則表達式
string 要匹配的字符串
flags 標誌位,用於控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等等

匹配成功re.search方法返回一個匹配的對象,否則返回None。

我們可以使用group(num) 或 groups() 匹配對象函數來獲取匹配表達式。

匹配對象方法 描述
group(num=0) 匹配的整個表達式的字符串,group() 可以一次輸入多個組號,在這種情況下它將返回一個包含那些組所對應值的元組。
groups( ) 返回一個包含所有小組字符串的元組,從 1 到 所含的小組號。
import re
print(re.search('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span())  # 不在起始位置匹配

執行效果如下:
在這裏插入圖片描述
讀者可以將這個例子的search和match對照着執行,會發現search在起始位置沒有匹配到是會接着往下匹配,直到真的沒有匹配到纔會返回None,而match在起始位置沒有匹配到時就直接返回None。因此如果沒有在起始位置匹配時,match接收到的是None,不能再調用span()。

3.3 re.match與re.search的區別

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

import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
    print("match --> matchObj.group() : ", matchObj.group())
else:
    print("match --> matchObj.group() : No match!!")

matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
    print("search --> matchObj.group() : ", matchObj.group())
else:
    print("search --> matchObj.group() : No match!!")

執行效果如下:
在這裏插入圖片描述

3.4 檢索和替換

Python 的 re 模塊提供了re.sub用於替換字符串中的匹配項。

函數語法:

re.sub(pattern, repl, string, count=0, flags=0)

函數參數說明:

參數 說明
pattern 正則中的模式字符串。
repl 替換的字符串,也可爲一個函數。
string 要被查找替換的原始字符串。
count 模式匹配後替換的最大次數,默認 0 表示替換所有的匹配。
import re
phone = "2004-959-559 # 這是一個國外電話號碼"

# 刪除字符串中的 Python註釋
num = re.sub(r'#.*$', '', phone)
print("電話號碼是: ", num)

# 刪除非數字(-)的字符串 
num = re.sub(r'\D','', phone)
print("電話號碼是 : ", num)

執行效果如下:

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章