正則表達式匹配複習python
利用括號分組正則表達式
假定想要將區號從電話號碼中分離。添加括號將在正則表達式中建立「分組」:(\d\d\d)-(\d\d\d-\d\d\d)。而後使用group()匹配對象方法,從一個分組中獲取匹配的文本。
正則表達式字符串中的第一對括號是第1組。第二對括號是第2組。向group()匹配對象方法傳入整數1或者2,就能夠匹配文本的不一樣部分。向group()方法中傳入0或者不傳入參數,將返回整個匹配的文本。app
>>> import re >>> phoneNumberRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d)') >>> mo = phoneNumberRegex.search('my number is 415-555-4242.') >>> mo.group(1) '415' >>> mo.groups() ('415', '555-424')
>>> heroRegex = re.compile(r'batman|tina fey') >>> mo1 = heroRegex.search('batman and tina fey') >>> mo1.group() 'batman' >>> mo1 = heroRegex.search(' tina fey and batman ') >>> mo1.group() 'tina fey'
能夠試用管道來匹配多個模式中的一個,做爲正則表達式的一部分。函數
>>> batRegex = re.complie(r'bat(man|mobile|copter|bat)') >>> batRegex = re.compile(r'bat(man|mobile|copter|bat)') >>> mo = batRegex.search('batmobile lost a wheel') >>> mo.group() 'batmobile' >>> mo.group(1) 'mobile' >>>
用問號實現可選匹配spa
有時候,向匹配的模式是可選的。就是說,不論這段文本在不在,正則表達式都會認爲匹配。字符?代表它前面的分組在這個模式中是可選的。code
>>> phoneNumberRegex = re.compile(r'(\d\d\d-)?\d\d\d-\d\d\d') >>> mo = phoneNumberRegex.search('my number is 415-555-4242.') >>> mo.group() '415-555-424' >>> mo = phoneNumberRegex.search('my number is 555-4242.') >>> mo.group() '555-424'
正則表達式中(\d\d\d-)?部分代表,模式(\d\d\d-)是可選的。也就是匹配這個問號以前的分組零次或一次對象
用星號匹配零次或屢次ip
「*」星號以前的分組,能夠在文本中出現任意次。字符串
用加號匹配一次或屢次it
「+」加號以前的分區,至少在文本中出現一次
用花括號匹配特定的次數
若是想要一個分組重複特定的次數,就在正則表達式中該分組的後面,跟上畫括號包圍的數字。例如正則表達式(Ha){3}將匹配字符串'HaHaHa'
除了一個數字,還能夠指定給一個範圍,即在花括號中寫下一個最小值、一個逗號和一個最大值。例如在正則表達(Ha){3,5}將匹配'HaHaHa','HaHaHaHa','HaHaHaHaHaHa'
也能夠不謝花括號中第一個或第二個數字,不限定最小值或最大值。例如(Ha){3,}將匹配3次或者更屢次的實例,(Ha){,5}將匹配0到5次實例。
貪心匹配和非貪心匹配
python的正則表達式模式的是「貪心」的,這表示在有二意的狀況下,他們會盡量的匹配最長的字符串。花括號的「非貪心」版本匹配儘量最短的字符串,即在結束的花括號後跟着一個問號。
問號在正則表達式中有兩種含義:聲明非貪心匹配或表示可選的分組。
findall()方法
除了search方法外,Regex對象也有一個findall()方法。search()將返回一個Match對象,包含被查找字符串中的「第一次」匹配的文本,而findall()方法將返回一組字符串,包含被查找字符串中的全部匹配。
字符分類
縮寫字符分類 | 表示 |
---|---|
\d | 0到9的任何數字 |
\D | 除0到9的數字之外的任何字符 |
\w | 任何字母、數字或下劃線字符(能夠認爲是匹配「單詞」字符 |
\W | 除字母、數字和下劃線之外的任何字符 |
\s | 空格、製表符或換行符(能夠認爲是匹配「空白」字符) |
\S | 除空格、製表符和換行符之外的任何字符 |
創建本身的字符分類
#匹配全部非元音字符 >>> consonantRegex = re.compile(r'[^aeiouAEIOU]') >>> consonantRegex.findall('RoboCop eats baby food. BABY FOOD.') ['R', 'b', 'C', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
插入字符和美圓字符
能夠在正則表達式的開始處使用插入符號(^ ),代表匹配必須發生在被查找文本開始處。相似地,能夠再正則表達式的末尾加上美圓符號($),表示該字符串必須以這個正則表達式的模式結束。能夠同時使用^和$,代表整個字符串必須匹配該模式,也就是說,只匹配該字符串的某個子集是不夠的。
>>> beginsWithHello = re.compile(r'^Hello') >>> beginsWithHello.search('Hello world!') <_sre.SRE_Match object; span=(0, 5), match='Hello'> >>> hh=beginsWithHello.search('Hello world!') >>> hh.group() 'Hello' >>> endsWithNumber = re.compile(r'\d$') >>> ss=endsWithNumber.search('Your number is 42') >>> ss.group() '2' >>> wholeStringIsNum = re.compile(r'^\d+$') >>> rr=wholeStringIsNum.search('1234567890') >>> rr.group() '1234567890'
通配字符
在正則表達式中,.(句點)字符稱爲「通配符」。它匹配除了換行以外的全部 字符。
>>> atRegex = re.compile(r'.at') >>> atRegex.findall('The cat in the hat sat on the flat mat.') ['cat', 'hat', 'sat', 'lat', 'mat']
句點字符只匹配一個字符,這就是爲何在前面的例子中,對於文本flat,只匹配 lat。
用點-星匹配全部字符
有時候想要匹配全部字符串。例如,假定想要匹配字符串'First Name:',接下來是任意文本,接下來是'Last Name:',而後又是任意文本。能夠用點-星(.*)表示「任意文本」。回憶一下,句點字符表示「除換行外全部單個字符」,星號字符表示「前面字符出現零次或屢次」。
>>> nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)') >>> mo = nameRegex.search('First Name: Al Last Name: Sweigart') >>> mo.group(1) 'Al' >>> mo.group(2) 'Sweigart'
用句點字符匹配換行
點-星將匹配除換行外的全部字符。經過傳入 re.DOTALL 做爲 re.compile()的第二個參數,可讓句點字符匹配全部字符,包括換行字符。
>>> noNewlineRegex = re.compile('.*') >>> noNewlineRegex.search('Serve the public trust.\nProtect the innocent. \nUphold the law.').group() 'Serve the public trust.' >>> newlineRegex = re.compile('.*', re.DOTALL) >>> newlineRegex.search('Serve the public trust.\nProtect the innocent. \nUphold the law.').group() 'Serve the public trust.\nProtect the innocent.\nUphold the law.'
正則表達式符號複習
不區分大小寫的匹
向re.comlile()傳入re.IGNORECASE或re.I,做爲第二個參數
用sub()方法替換字符串
Regex對象的sub()方法須要傳入兩個參數。第一個參數是字符串,用於取代發現的匹配。第二個參數是一個字符串,即正則表達式。sub()方法返回替換完成後的字符串。
>>> namesRegex = re.compile(r'Agent \w+') >>> namesRegex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.') 'CENSORED gave the secret documents to CENSORED.'
有時候,你可能須要使用匹配的文本自己,做爲替換的一部分。在 sub()的第一個參數中,能夠輸入\一、\二、\3……。表示「在替換中輸入分組一、二、3……的文本」。
例如,假定想要隱去密探的姓名,只顯示他們姓名的第一個字母。要作到這一點,可使用正則表達式 Agent (\w)\w*,傳入 r'\1****'做 sub()的第一個參數。字符串中的\1 將由分組 1匹配的文本所替代,也就是正則表達式的(\w)分組。
>>> agentNamesRegex = re.compile(r'Agent (\w)\w*') >>> agentNamesRegex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eve knew Agent Bob was a double agent.') A**** told C**** that E**** knew B**** was a double agent.'
若是要匹配的文本模式很簡單,正則表達式就很好。但匹配複雜的文本模式,可能須要長的、費解的正則表達式。你能夠告訴re.compile(),忽略正則表達式字符串中的空白符和註釋,從而緩解這一點。要實現這種詳細模式,能夠向 re.compile() 傳入變量 re.VERBOSE,做爲第二個參數。
項目 電話號碼和 E-mail 地址提取程序 假設你有一個無聊的任務,要在一篇長的網頁或文章中,找出全部電話號碼和郵件地址。若是手動翻頁,可能須要查找很長時間。若是有一個程序,能夠在剪貼板的文本中查找電話號碼和 E-mail地址,那你就只要按一下Ctrl-A選擇全部文本,按下 Ctrl-C 將它複製到剪貼板,而後運行你的程序。它會用找到的電話號碼和 E-mail地址,替換掉剪貼板中的文本。
import re import pyperclip phoneRegex = re.compile(r'''( (\d{3}|\(\d{3}\))? (\s\|-|\.)? (\d{3}) (\s|-|\.) (\d{4}) (\\s*(ext|x|ext.)\s*(\d{2,5}))? )''', re.VERBOSE) emailRegex = re.compile(r''' ([a-zA-Z0-9._%+-]+ @ [a-zA-Z0-9.-]+ (\.[a-zA-Z]{2,4}) )''', re.VERBOSE) text = str(pyperclip.paste()) matches = [] for groups in phoneRegex.findall(text): phoneNum = '-'.join([groups[1],groups[3],groups[5]]) if groups[8] != '': phoneNum += 'x' + groups[8] matches.append(phoneNum) for groups in emailRegex.findall(text): matches.append(groups[0]) if len(matches) >0: pyperclip.copy('\n'.join(matches)) print('Copied to clipboard :') print('\n'.join(matches)) else: print('No phone numbers or email addresses found.')