原文轉自 :https://blog.csdn.net/Ruger00...html
正則表達式,又稱正規表示式、正規表示法、正規表達式、規則表達式、常規表示法(英語:Regular Expression,在代碼中常簡寫爲regex、regexp或RE),計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列匹配某個句法規則的字符串。在不少文本編輯器裏,正則表達式一般被用來檢索、替換那些匹配某個模式的文本。java
許多程序設計語言都支持利用正則表達式進行字符串操做。例如,在Perl中就內建了一個功能強大的正則表達式引擎。正則表達式這個概念最初是由Unix中的工具軟件(例如sed和grep)普及開的。正則表達式一般縮寫成「regex」,單數有regexp、regex,複數有regexps、regexes、regexen。python
import re key = r"<html><body><h1>hello world<h1></body></html>"//這段是你要匹配的文本 p1 = r"(?<=<h1>).+?(?=<h1>)"//這是咱們寫的正則表達式規則,你如今能夠不理解啥意思 pattern1 = re.compile(p1)//咱們在編譯這段正則表達式 matcher1 = re.search(pattern1,key)//在源文本中搜索符合正則表達式的部分 print matcher1.group(0)//打印出來
你能夠嘗試運行上面的代碼,看看是否是和咱們想象的同樣(博主是在python2.7環境下)發現代碼挺少挺簡單?往下看。並且正則表達式實際上要比看起來的那種奇形怪狀要簡單得多。ios
首先,從最基礎的正則表達式提及。
假設咱們的想法是把一個字符串中的全部」python」給匹配到。咱們試一試怎麼作程序員
import re key = r"javapythonhtmlvhdl"#這是源文本 p1 = r"python"#這是咱們寫的正則表達式 pattern1 = re.compile(p1)#一樣是編譯 matcher1 = re.search(pattern1,key)#一樣是查詢 print matcher1.group(0)
看完這段代碼,你是否是以爲:臥槽?這就是正則表達式?直接寫上去就行?正則表達式
確實,正則表達式並不像它表面上那麼奇葩,若是不是咱們故意改變一些符號的含義時,你看到的就是想要匹配的。編程
因此,先把大腦清空,先認爲正則表達式就是和想要匹配的字符串長得同樣。在以後的練習中咱們會逐步進化python2.7
不管是python仍是正則表達式都是區分大小寫的,因此當你在上面那個例子上把」python」換成了」Python」,那就匹配不到你心愛的python了。編輯器
從新回到第一個例子中那個< h1 >hello world< h1 >
匹配。假如我像這麼寫,會怎麼樣?工具
import re key = r"<h1>hello world<h1>"#源文本 p1 = r"< h1 >.+< h1 >"#咱們寫的正則表達式,下面會將爲何 pattern1 = re.compile(p1) print pattern1.findall(key)#發沒發現,我怎麼寫成findall了?咋變了呢?
有了入門級的經驗,咱們知道那兩個< h1 >就是普普統統的字符,可是中間的是什麼鬼?
.字符在正則表達式表明着能夠表明任何一個字符(包括它自己)
findall返回的是全部符合要求的元素列表,包括僅有一個元素時,它仍是給你返回的列表。
機智如你可能會忽然問:那我若是就只是想匹配」.」呢?結果啥都給我返回了咋整?在正則表達式中有一個字符,其實若是你編程經驗較多的話,你就會發現這是好多地方的「轉義符」。在正則表達式裏,這個符號一般用來把特殊的符號轉成普通的,把普通的轉成特殊的23333(並非特殊的「2333」,寫完才發現會不會有腦洞大的想歪了)。
舉個栗子,你真的想匹配」chuxiuhong@hit.edu.cn」這個郵箱(個人郵箱),你能夠把正則表達式寫成下面這個樣子:
import re key = r"afiouwehrfuichuxiuhong@hit.edu.cnaskdjhfiosueh" p1 = r"chuxiuhong@hit\.edu\.cn" pattern1 = re.compile(p1) print pattern1.findall(key)
發現了吧,咱們在.的前面加上了轉義符,可是並非表明匹配「.」的意思,而是隻匹配「.」的意思!
不知道你細不細心,有沒有發現咱們第一次用.時,後面還跟了一個+?那這個加號是幹什麼的呢?
其實不難想,咱們說了「.字符在正則表達式表明着能夠表明任何一個字符(包括它自己)」,可是」hello world」可不是一個字符啊。
+的做用是將前面一個字符或一個子表達式重複一遍或者多遍。
比方說表達式「ab+」那麼它能匹配到「abbbbb」,可是不能匹配到」a」,它要求你必須得有個b,多了不限,少了不行。你若是問我有沒有那種「有沒有都行,有多少都行的表達方式」,回答是有的。
*跟在其餘符號後面表達能夠匹配到它0次或屢次
比方說咱們在網頁內遇到了連接,可能既有http://開頭的,又有https://開頭的,咱們怎麼處理?
import re key = r"http://www.nsfbuhwe.com and https://www.auhfisna.com"#胡編亂造的網址,別在乎 p1 = r"https*://"#看那個星號! pattern1 = re.compile(p1) print pattern1.findall(key)
輸出
['http://', 'https://']
比方說咱們有這麼一個字符串」cat hat mat qat」,你會發現前面三個是實際的單詞,最後那個是我胡編亂造的(上百度查完是昆士蘭英語學院的縮寫= =)。若是你原本就知道」at」前面是c、h、m其中之一時這才構成單詞,你想把這樣的匹配出來。根據已經學到的知識是否是會想到寫出來三個正則表達式進行匹配?實際上不須要。由於有一種多字符匹方式
[]表明匹配裏面的字符中的任意一個
仍是舉個栗子,咱們發現啊,有的程序員比較過度,,在這對標籤上,大小寫混用,老害得咱們抓不到想要的東西,咱們該怎麼應對?是寫16*16種正則表達式挨個匹配?no
import re key = r"lalala<hTml>hello</Html>heiheihei" p1 = r"<[Hh][Tt][Mm][Ll]>.+?</[Hh][Tt][Mm][Ll]>" pattern1 = re.compile(p1) print pattern1.findall(key)
輸出
['<hTml>hello</Html>']
咱們既然有了範圍性的匹配,天然有範圍性的排除。
[^]表明除了內部包含的字符之外都能匹配
仍是cat,hat,mat,qat這個例子,咱們想匹配除了qat之外的,那麼就應該這麼寫:
import re key = r"mat cat hat pat" p1 = r"[^p]at"#這表明除了p之外都匹配 pattern1 = re.compile(p1) print pattern1.findall(key)
爲了方便咱們寫簡潔的正則表達式,它自己還提供下面這樣的寫法
介紹到這裏,咱們可能已經掌握了大體的正則表達式的構造方式,可是咱們經常會在實戰中遇到一些匹配的不許確的問題。比方說:
import re key = r"chuxiuhong@hit.edu.cn" p1 = r"@.+\."#我想匹配到@後面一直到「.」之間的,在這裏是hit pattern1 = re.compile(p1) print pattern1.findall(key)
輸出
['@hit.edu.']
呦呵!你咋能多了呢?我理想的結果是@hit.,你咋還給我加量了呢?這是由於正則表達式默認是「貪婪」的,咱們以前講過,「+」表明是字符重複一次或屢次。可是咱們沒有細說這個屢次究竟是多少次。因此它會盡量「貪婪」地多給咱們匹配字符,在這個例子裏也就是匹配到最後一個「.」。
咱們怎麼解決這種問題呢?只要在「+」後面加一個「?」就行了。
import re key = r"chuxiuhong@hit.edu.cn" p1 = r"@.+?\."#我想匹配到@後面一直到「.」之間的,在這裏是hit pattern1 = re.compile(p1) print pattern1.findall(key)
輸出結果
['@hit.']
加了一個「?」咱們就將貪婪的「+」改爲了懶惰的「+」。這對於[abc]+,w*之類的一樣適用
我的建議:在你使用」+」,」*」的時候,必定先想好究竟是用貪婪型仍是懶惰型,尤爲是當你用到範圍較大的項目上時,由於頗有可能它就多匹配字符回來給你!!!
爲了可以準確的控制重複次數,正則表達式還提供
{a,b}(表明a<=匹配次數<=b)
仍是舉個栗子,咱們有sas,saas,saaas,咱們想要sas和saas,咱們怎麼處理呢?
import re key = r"saas and sas and saaas" p1 = r"sa{1,2}s" pattern1 = re.compile(p1) print pattern1.findall(key)
若是你省略掉{1,2}中的2,那麼就表明至少匹配一次,那麼就等價於?
若是你省略掉{1,2}中的1,那麼就表明至多匹配2次。
下面列舉一些正則表達式裏的元字符及其做用