這篇文章分為幾個(gè)部分:
1,遇到的文本處理的問(wèn)題
2,正則能夠解決的和不能解決的
3,正則的基本知識(shí)
4,python中re正則模塊的學(xué)習(xí)
5,結(jié)合一些實(shí)例,用正則完整分析一個(gè)問(wèn)題
6,有哪些不用正則也可以很好解決的
7,回顧和思考
8,資源
其中第1,2,5,6,7可能要不斷更新的。
1.1 將一個(gè)字符串中的所有中文標(biāo)點(diǎn)符號(hào)替換為英文的。
1.2 將字符串中某些詞替換為另外一個(gè)詞
1.3 刪除字符串中的某些詞
[注]這部分引用了
正則表達(dá)式 – 語(yǔ)法
正則表達(dá)式30分鐘入門(mén)教程
3.1 正則是什么
正則表達(dá)式(regular expression)描述了一種字符串匹配的模式,可以用來(lái)檢查一個(gè)串是否含有某種子串、將匹配的子串做替換或者從某個(gè)串中取出符合某個(gè)條件的子串等。
3.2 一個(gè)簡(jiǎn)單的例子
從一段英語(yǔ)文字中找到單詞hi,咋一看很簡(jiǎn)單,如果是在python中你可能只需要用str.find('hi')
就可以找到它的第一個(gè)位置了,但除非你的句子中沒(méi)有hight,shift…
包含hi的詞,除非你不把Hi、HI也當(dāng)成hi,除非…
使用正則表達(dá)式只要用bhib
就可以表達(dá)這個(gè)意思。首先,正則表達(dá)式會(huì)自動(dòng)幫我們忽略大小寫(xiě),然后,b
是正則表達(dá)式規(guī)定的一個(gè)特殊代碼,代表著單詞的開(kāi)頭或結(jié)尾,也就是單詞的分界處,代表著hi這個(gè)詞前后都被空格、逗號(hào)等等分割。
也就是說(shuō)當(dāng)我們要處理一段文本得到我們想要的東西的時(shí)候,要求太多,我們以為理所當(dāng)然的事情計(jì)算機(jī)不會(huì),我們需要用一套機(jī)制告訴它我們認(rèn)為理所應(yīng)當(dāng)?shù)囊?guī)則,這就是正則表達(dá)式,它高度抽象、非常不好寫(xiě)。所以我們需要一個(gè)工具下載Regex Tester幫助我們,大概是這樣的:
3.3 怎樣寫(xiě)正則表達(dá)式
正則表達(dá)式是由普通字符(例如字符 a 到 z)以及特殊字符(稱(chēng)為”元字符”)組成的文字模式。
正常的英語(yǔ)都是以a-z 26個(gè)字母組成的,而正則語(yǔ)句是由普通字符和元字符組成的,其中:
普通字符:所有大寫(xiě)和小寫(xiě)字母、所有數(shù)字、所有標(biāo)點(diǎn)符號(hào)和一些其他符號(hào)。
元字符:按功能分類(lèi),它包括 非打印字符、特殊字符、限定符、定位符、
字符 | 描述 |
cx | 匹配由x指明的控制字符。例如, cM 匹配一個(gè) Control-M 或回車(chē)符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個(gè)原義的 ‘c’ 字符。 |
f | 匹配一個(gè)換頁(yè)符。等價(jià)于 x0c 和 cL。 |
n | 匹配一個(gè)換行符。等價(jià)于 x0a 和 cJ。 |
r | 匹配一個(gè)回車(chē)符。等價(jià)于 x0d 和 cM。 |
s | 匹配任何空白字符,包括空格、制表符、換頁(yè)符等等。等價(jià)于 [ fnrtv]。 |
S | 匹配任何非空白字符。等價(jià)于 1。 |
t | 匹配一個(gè)制表符。等價(jià)于 x09 和 cI。 |
v | 匹配一個(gè)垂直制表符。等價(jià)于 x0b 和 cK。 |
特別字符 | 描述 |
$ | 匹配輸入字符串的結(jié)尾位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,則 $ 也匹配 ‘n’ 或 ‘r’。要匹配 $ 字符本身,請(qǐng)使用 $。 |
( ) | 標(biāo)記一個(gè)子表達(dá)式的開(kāi)始和結(jié)束位置。子表達(dá)式可以獲取供以后使用。要匹配這些字符,請(qǐng)使用 ( 和 )。 |
* | 匹配前面的子表達(dá)式零次或多次。要匹配 * 字符,請(qǐng)使用 *。 |
+ | 匹配前面的子表達(dá)式一次或多次。要匹配 + 字符,請(qǐng)使用 +。 |
. | |
[ | 標(biāo)記一個(gè)中括號(hào)表達(dá)式的開(kāi)始。要匹配 [,請(qǐng)使用 [。 |
匹配前面的子表達(dá)式零次或一次,或指明一個(gè)非貪婪限定符。要匹配 ? 字符,請(qǐng)使用 ?。 | |
| 5789536e17c4d1581d5e6e1dc5484afa163 | 將下一個(gè)字符標(biāo)記為或特殊字符、或原義字符、或向后引用、或八進(jìn)制轉(zhuǎn)義符。例如, ‘n’ 匹配字符 ‘n’?!痭’ 匹配換行符。序列 ” 匹配 “”,而 ‘(‘ 則匹配 “(“。 |
^ | 匹配輸入字符串的開(kāi)始位置,除非在方括號(hào)表達(dá)式中使用,此時(shí)它表示不接受該字符集合。要匹配 ^ 字符本身,請(qǐng)使用 ^。 |
{ | 標(biāo)記限定符表達(dá)式的開(kāi)始。要匹配 {,請(qǐng)使用 {。 |
| | 指明兩項(xiàng)之間的一個(gè)選擇。要匹配 |,請(qǐng)使用 |。 |
字符 | 描述 |
* | 匹配前面的子表達(dá)式零次或多次。例如,zo 能匹配 “z” 以及 “zoo”。 等價(jià)于{0,}。 |
+ | 匹配前面的子表達(dá)式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等價(jià)于 {1,}。 |
匹配前面的子表達(dá)式零次或一次。例如,”do(es)?” 可以匹配 “do” 或 “does” 中的”do” 。? 等價(jià)于 {0,1}。 | |
{n} | n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的兩個(gè) o。 |
{n,} | n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o?!痮{1,}’ 等價(jià)于 ‘o+’?!痮{0,}’ 則等價(jià)于 ‘o*’。 |
{n,m} | m 和 n 均為非負(fù)整數(shù),其中n |
字符 | 描述 |
^ | 匹配輸入字符串開(kāi)始的位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,^ 還會(huì)與 n 或 r 之后的位置匹配。 |
$ | 匹配輸入字符串結(jié)尾的位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,$ 還會(huì)與 n 或 r 之前的位置匹配。 |
b | 匹配一個(gè)字邊界,即字與空格間的位置。 |
B | 非字邊界匹配。 |
正則在python中是通過(guò)re
模塊實(shí)現(xiàn)的。文檔
下面給出re
核心函數(shù)和方法
1 | **`re` 模塊的函數(shù) 描述** |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | complie(pattern,flags=0) 對(duì)正則表達(dá)式模式 pattern 進(jìn)行編譯,flags 是可選標(biāo)志符,并返回一個(gè) regex 對(duì)象 match(pattern,string,flags=0) 用pattern匹配字符串 string,成功返回匹配對(duì)象,否則返回None search(pattern,string,flags=0) 在字符串 string 中查找正則表達(dá)式模式 pattern 的第一次出現(xiàn),匹配成功,返回一個(gè)匹配對(duì)象;否則返回 None findall(pattern,string[,flags]) 在字符串 string 中查找正則表達(dá)式模式 pattern 的所有(非重復(fù))出現(xiàn);返回一個(gè)匹配對(duì)象的列表 finditer(pattern,string,[,flags]) 和 findall()相同,但返回的不是列表而是迭代器;對(duì)于每個(gè)匹配,該迭代器返回一個(gè)匹配對(duì)象 split(pattern,string,max=0) 根據(jù)正則表達(dá)式 pattern 中的分隔符把字符 string 分割為一個(gè)列表,返回成功匹配的列表,最多分割 max 次(默認(rèn)是分割所有匹配的地方)。 sub(pattern,repl,string,max=0) 把字符串 string 中所有匹配正則表達(dá)式 pattern 的地方替換成字符串 repl,如果 max 的值沒(méi)有給出, 則對(duì)所有匹配的地方進(jìn)行替換。 group(num=0) 返回全部匹配對(duì)象(或指定編號(hào)是 num 的子組) groups() 返回一個(gè)包含全部匹配的子組的元組(如果沒(méi)成功匹配,就返回一個(gè)空元組) |
1. 使用 compile()編譯正則表達(dá)式
為什么要編譯:正則表達(dá)式模式使用前必須先被編譯成 regex 對(duì)象,也就是說(shuō)每次使用都要編譯一次,那還不如先編譯,然后隨時(shí)用起來(lái),省時(shí)省空間。
原本是這樣:
1 2 3 4 | result1=re.match(pattern,string1) result2=re.match(pattern,string2) result3=re.match(pattern,string3) ... |
現(xiàn)在是這樣:
1 2 3 4 5 | prog = re.compile(pattern) result1 = prog.match(string1) result2 = prog.match(string2) result3 = prog.match(string3) ... |
結(jié)果是不用每次都要將pattern
作為參數(shù)放入函數(shù)中去了,大大節(jié)省時(shí)間。
2. 用 match()匹配字符串
簡(jiǎn)單:
1 2 3 4 5 6 7 8 | m = re.match('foo', 'foo') # pattern matches string ,模式匹配字符串 if m is not None: # show match if successful 如果成功,顯示匹配 m.group()#group()返回全部對(duì)象 'foo' m = re.match('foo', 'bar')# pattern does not match string 模式不匹配字符串 m#None m = re.match('foo', 'food on the table') # match succeeds # 匹配成功 m.group()#'foo' |
+正則:
3. 用search()匹配字符串
1 2 | 其實(shí),你要搜索的模式出現(xiàn)在一個(gè)字符串中間的機(jī)率要比出現(xiàn)在字符串開(kāi)頭的機(jī)率更大一些。 這正是 search()派上用場(chǎng)的時(shí)候。search 和 match 的工作方式一樣,不同之處在于 search 會(huì)檢查參數(shù)字符串任意位置的地方給定正則表達(dá)式模式的匹配情況。如果搜索到成功的匹配,會(huì)返回一個(gè)匹配對(duì)象,否則返回 None。 |
現(xiàn)在我們來(lái)舉例說(shuō)明 match()和 search()之間的區(qū)別。我們用字符串”foo”去匹配“seafood”:
1 2 3 4 5 | m = re.match('foo', 'seafood') # no match 匹配失敗 m#None m = re.search('foo', 'seafood') # use search() instead 改用 search() if m is not None: m.group() 'foo'#匹配成功 |
4. 用findall()匹配字符串
1 2 | 它用于非重疊地查找某字符串中一個(gè)正則表達(dá)式模式出 現(xiàn)的情況。findall()和 search()相似之處在于二者都執(zhí)行字符串搜索,但 findall()和 match()與search()不同之處是,findall()總返回一個(gè)列表。如果 findall()沒(méi)有找到匹配的部分,會(huì)返回空列表;如果成功找到匹配部分,則返回所有匹配部分的列表(按從左到右出現(xiàn)的順序排列)。 |
1 2 | re.findall('car', 'carry the barcardi to the car') ['car', 'car', 'car'] |
5. 用 split()分割(分隔模式)
1 | re 模塊和正則表達(dá)式對(duì)象的方法 split()與字符串的 split()方法相似, 前者是根據(jù)正則表達(dá)式模式分隔字符串,后者是根據(jù)固定的字符串分割,因此與后者相比,顯著提升了字符分割的能力。 |
1 2 | re.split(':', 'str1:str2:str3') ['str1', 'str2', 'str3'] |
6. 用 sub()[和 subn()]進(jìn)行搜索和替換
1 | 二者幾乎是一樣的,都是將某字符串中所有匹配正則表達(dá)式模式的部分進(jìn)行替換。用來(lái)替換的部分通常是一個(gè)字符串,但也可能是一個(gè)函數(shù),該函數(shù)返回一個(gè)用來(lái)替換的字符串。subn()和 sub()一樣,但它還返回一個(gè)表示替換次數(shù)的數(shù)字,替換后的字符串和表示替換次數(shù)的數(shù)字作為一個(gè)元組的元素返回。 |
1 2 3 | re.sub('l','L','hello') heLLo |
前幾天處理了一個(gè)小問(wèn)題,問(wèn)題描述如下:
問(wèn)題:字符串s有兩種內(nèi)容,一種是’客車(chē)’,一種是’4排5座SUV’,如果是’客車(chē)’原樣返回,如果是
‘4排5座SUV’,則將字符串’4排5座SUV’中的’5座’單獨(dú)提取出來(lái),這個(gè)問(wèn)題很簡(jiǎn)單先用if語(yǔ)句解決
‘客車(chē)’,在查看’4排5座SUV’中文和英文的字符長(zhǎng)度,用切片選出來(lái)就行,解決如下:
1 2 3 4 5 6 7 | try: if s=='客車(chē)': return s else: return s[3:6] except: return '' |
其實(shí)用正則可以輕松解決:
1 2 3 4 5 6 | import re split=re.compile('\d座|客車(chē)') try: result=split.search(s).group() except: result='' |
使用正則的好處:
1,不需要先知道要匹配字符的位置如[3:6],如果要匹配很多條結(jié)果用切片法肯定很亂。
2,更加靈活,如果出現(xiàn)’¥%……4排5座SUV’也可以成功匹配
3,預(yù)先編譯,更高效
聯(lián)系客服