1. 程式人生 > >正則表示式-Python實現

正則表示式-Python實現

1、概述:

Regular Expression。縮寫regex,regexp,R等:

正則表示式是文字處理極為重要的工具。用它可以對字串按照某種規則進行檢索,替換。

Shell程式設計和高階程式語言中都支援正則表示式。

2、分類:

BRE:基本正則表示式,grep、sed、vi等軟體支援,vim有擴充套件。

ERE:擴充套件正則表示式,egrep(grep-E)、sed-r。

PCRE:  re模組。Python中。幾乎所有高階語言都是PCRE的方言或者變種。

3、基本語法

1)元字元

程式碼

說明

舉例

.

匹配除換行符外任意一個字元

.

[abc]

字元集合,只能表示一個字元位置。匹配所包含的任意一個字元

[abc]匹配plain中的’a’

[^abc]

字元集合,只能表示一個字元位置,匹配除去集合內字元的任意一個字元。

[^abc]可以匹配plain中’p’,’l’,’i’或者’n’

 

[a-z]

字元範圍,也是個集合,表示一個字元位置,匹配所包含的任意一個字元。

[a-d]可以匹配plain中的’a’

 

[^a-z]

字元範圍,也是個集合,表示一個字元位置,匹配除去集合內字元的任意一個字元。

[a-d]可以匹配plain的中’p’,’l’,’i’或者’n’

 

\b

匹配單詞的邊界

\ba在文字中找到單詞a開頭的,a\b找到以a結尾的。

\B

不匹配單詞的邊界

t\B包含t的單詞但是不以t結尾,write

\Bb不以b開頭但是包含b的單詞,able

\d

[0-9]匹配1位數字

\d

\D

[^0-9]匹配一位非數字

 

\w

匹配[a-zA-Z0-9],包括中文的字

\w

\W

匹配\w之外的字元。

 

\s

匹配1位空白字元,包括換行符,製表符、空格[\f\r\n\t\v]

 

\S

匹配非空白字元。

 

2)轉義

凡是在正則表示式中有特殊意義的符號,如果想使用它他的本意,使用\轉義,反斜槓自身,得使用\\   \r 轉義後代表回車   \n  換行

3)重複

程式碼

說明

舉例

*

表示前面的正則表示式會重複0次或者多次

e\w*單詞e中可以有非空白字元。

+

表示前面的正則表示式重複至少1次

e\w+單詞e後面至少有一個非空白字元。

表示前面的正則表示式會重複0次或者1次

e\w?單詞e後面至多有一個非空白字元。

{n}

重複固定的n次

e \w{1}單詞中e後面只能有一個非白字元。

{n,}

重複至少n次

e \w{1,} >>>e\w+

e\w{0,}>>>e\w*

e \w{0,1}>>>e\w?

{n,m}

重複n到m次

e \w{1,10}單詞後面至少一個,至多10個非空白字元。

4)基本練習:

(1)匹配手機號碼:

\d{11,}

(2)匹配中國座機:

\d{3,4}-\d{7,8}

5)原始碼

程式碼

說明

舉例

x | y

匹配x或者y

Wood  took foot food

使用w|food  或者(w|f)odd

捕獲

 

 

(pattern)

使用小括號指定一個字表達式,也叫分組捕獲後會自動分配組號從1開始,可以改變優先順序

 

\數字

匹配對應的分組

(very)\1匹配very very,但捕獲的組group是very。

(?:pattern)

如果僅僅為了改變優先順序,就不需要捕獲分組

(?:w|f)ood  ‘industr(?:y|lies)’等價於’industry|industries’

(?<name>exp)(?’name’exp)

分組捕獲,但是可以通過name訪問分組。Python的語法必須是(?P<name>exp)

 

零寬斷言

 

 

(?=exp)

零寬度正測先行斷言:

斷言exp一定在匹配的右邊出現,也就是說斷言後面一定跟個exp

f(?=00)f後面一定有oo出現

(?<=exp)

零寬度正回顧後發斷言:

斷言exp一定出現在匹配的左邊出現。也就是說前面一定有個exp字首

(?<=f)ood,(?<=t)ook分別匹配ood,ook,ook前面一定有t出現。

負向零寬斷言

 

 

(?!exp)

零寬度負預測先行斷言;

斷言一定不會出現在右側,也就是說斷言後面一定不是exp

\d{3}(?!\d)匹配三位數字,斷言三位數字後面一定不能是數字

(?<!exp)

零寬度負回顧後發斷言

斷言exp一定不能出現在左側,也就是說斷言前面一定不能是exp

(?<!f)ood ood 的左邊一定不是f

註釋

 

 

(?#comment)

註釋

 

斷言不佔分組號,斷言如同條件,只是要求匹配必須滿足斷言條件。

分組和捕獲是同一個意思;

使用正則表示式時候,能用簡單表示式,就不要複雜的表示式。

6)貪婪與非貪婪;

程式碼

說明

舉例

*?

匹配任意次,但是儘可能少重複

*?儘可能的少,可以是沒有。

 

+?

匹配至少1次,但是儘可能少重複

+?至少一次。

 

??

匹配0次或者1次,儘可能少重複

??儘可能的少,至少0次。

 

{n,}?

匹配至少n次,儘可能沒有

 

{n,m}

至少匹配n次,至多m次,儘可能少重複

 

 

Very very very happy

V.*y  和v.*?y

7)引擎選項:

程式碼

說明

Python中

ignoreCase

匹配時忽略大小寫

re.l   re.lGNORECASE

Singleline

單行模式,可以匹配所有字元,包括\n

re.S    re.DOTALL

Multine

多行模式^,行首,$行尾

re.M   re.MULTLINE

lgnorePatternWhites

忽略表示式中的空白字元,如果要使用空白字元轉義,#可以用來做註釋

re.x

re.VERBOSE

8)總結:

單行模式;

.可以匹配所有字元,包括換行符

^表示整個字串的開頭,$整個字串的結尾。

多行模式:

.可以匹配除了換行符之外的字元。

^表示整個字串的開頭,$整個字串的結尾。

^表示整個字串的開始,$表示整個字串的結尾。開始指的是\n緊接著下一個字元,結束指的是/n前的字元。

可以認為,單行模式就如同看穿了換行符,所有文字就是一個長長的只有一行的字串,所有^表示整個字串的開頭,$整個字串的結尾。

多行模式,注意字串看不見的換行符,\r\n 會影響e$測試,e$只能匹配e\n.

 

*重複任意次    限制的話用*?  得到了限制。

預設是貪婪模式,也就是儘量多匹配長的字串。

9)練習題:

匹配一個0-9999之間的任意數字:

^([1-9]?\d\d?|\d)(?!\d)

匹配合法的ip地址:

(\d{1,3}\.){3}\d{1,3}

192.168.1.150

0.0.0.0

255.255.255.255

17.16.52.100

172.16.0.100

400.400.999.888

001.022.003.000

257.257.255.256

 

ip的驗證採用python 的socket模組.

選出含有ftp的連結。且檔案的型別是gz或者xz的。

.*ftp.*/([^/]*\.(?:gz|xz))

4、python的正則表示式

1)常量:r.M(re.MULTILINE)多行  r.S(re.DOTALL)單行。  r.L(re.IGNORECASE)忽略大小寫。  r.X(re.VERBOSE)忽略空白字元。  使用|或運算

2)方法、編譯:

re.compile(pattern,flags=0)

設定flag,編譯模式。返回正則表示式物件regex。

Pattern就是正則表示式的字串,flags是選項,正則表示式需要被編譯,為了提高效率,為了提高效率,這些編譯後的結果就會被儲存,下次使用同樣的pattern的時候,就會不需要再次編譯。

re的其他方法為了提高效率都呼叫了編譯方法,就是為了提速。

3)Re.matth(pattern,string,flags=0)匹配只是做了單次的匹配。從頭開始,從第一個字串匹配上。對匹配字串加上了一^字元。只是匹配了一次。

Regex.match編譯後可以調整位置(切片)可以設定開始和結束的位置。返回match物件   regex = re.compile

match必須是以他開頭的,指定索引。

4)re.search(pattern,string,flags=0)    全文搜尋,不限定在哪裡開始查詢,找到第一個匹配物件立即返回,找不到返回none。只是找第一個。

Regex.search()可以指定位置。

5)re.fullmatch(pattern,string,flags=0)完全匹配。

regex.fullmatch(string) 整個字串和正則表示式匹配。

import re
s = '''bottle\nbag\nbig\napple'''
for i,c in enumerate(s,1):
    print((i-1,c),end='\n' if i%8==0 else ' ')
print()


print('--match--')
result = re.match('b',s)
print(1,result)
result= re.match('a',s)
print(2,result)
result = re.match('^a',s,re.M)
print(3,result)
result = re.match('^a',s,re.S)
print(4,result)
regex = re.compile('a')
result =regex.match(s)
print(5,result)
result=regex.match(s,15)
print(6,result)

print('--search--')
result = re.search('a',s)
print(7,result)
regex = re.compile('b')
result=regex.search(s,1)
print(8,result)
regex=re.compile('^b',re.M)
result=regex.search(s)
print(8.5,result)
result=regex.search(s,8)
print(9,result)

print('--fullmatch--')
result=re.fullmatch('bag',s)
print(10,result)
regex=re.compile('bag')
result=regex.fullmatch(s)
print(11,result)
result = regex.fullmatch(s,7)
print(12,result)
result=regex.fullmatch(s,7)
print(13,result)

(0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b')

(8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a')

(16, 'p') (17, 'p') (18, 'l') (19, 'e')

--match--

1 <_sre.SRE_Match object; span=(0, 1), match='b'>

2 None

3 None

4 None

5 None

6 <_sre.SRE_Match object; span=(15, 16), match='a'>

--search--

7 <_sre.SRE_Match object; span=(8, 9), match='a'>

8 <_sre.SRE_Match object; span=(7, 8), match='b'>

8.5 <_sre.SRE_Match object; span=(0, 1), match='b'>

9 <_sre.SRE_Match object; span=(11, 12), match='b'>

--fullmatch--

10 None

11 None

12 None

13 None

 

6)、全文搜尋;

Re.findall(pattern,string,flags=0)全文搜尋,全部搜尋。   返回匹配項的列表

Regex.findall(string,)

Re.finditer()   返回匹配項的可迭代物件。返回的都是match物件

Regex.finditer()

import re
s = '''bottle\nbag\nbig\napple'''
for i,c in enumerate(s,1):
    print((i-1,c),end='\n' if i%8==0 else ' ')
print()

print('--findall--')
result = re.findall('b',s)
print(1,result)
regex = re.compile('^b')
result = regex.findall(s)
print(2,result)
regex=re.compile('^b',re.M)
result=regex.findall(s,7)
print(3,result)
regex=re.compile('^b',re.S)
result=regex.findall(s)
print(4,result)
regex=re.compile('^b',re.M)
result=regex.findall(s,7,10)
print(5,result)
print('--finder--')
result=regex.finditer(s)
print(1,type(result))
print(2,next(result))
print(3,next(result))

(0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b')

(8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a')

(16, 'p') (17, 'p') (18, 'l') (19, 'e')

--findall--

1 ['b', 'b', 'b']

2 ['b']

3 ['b', 'b']

4 ['b']

5 ['b']

--finder--

1 <class 'callable_iterator'>

2 <_sre.SRE_Match object; span=(0, 1), match='b'>

3 <_sre.SRE_Match object; span=(7, 8), match='b'>

 

 

 

5、匹配替換:

re.sub(pattern,repleacement,string,count=0,flags=0)   替換

regex.sub(replacement,string,count=0)  替換

使用pattern對字串string進行匹配,對匹配項使用replancement替換吧,可以是string,bytes,function。

re.subn(pattern,replacement,string,count=0,flags=0)輸出二元組,提供替換的次數。

regex.subn(replacement,string,count=0,flags=0)

regex = re.compile('b\wg')
result = regex.sub('magedu',s)
print(1,result)
result = regex.sub('magedu',s,1)
print((2,result))

regex =re.compile('\s+')
result = regex.subn('\t',s)
print(3,result)

1 bottle

magedu

magedu

apple

(2, 'bottle\nmagedu\nbig\napple')

3 ('bottle\tbag\tbig\tapple', 3)

 

6、分隔字串:

Re.split(pattern,string,maxsplit=0,flag=0)

Re.split分隔字串

import re

s= '''01  bottle
02 bag
03        big1
100    able'''

x = re.split('\s+\d+\s+',' '+s)
print(x)

['', 'bottle', 'bag', 'big1', 'able']

 

7、分組:

使用小括號的pattern捕獲的資料放到了組group中。

Match,search函式均可以返回match物件。Findall返回的是字串列表。。Finditer一個個返回match物件。。

如果pattern中使用了分組,如果有匹配結果,會在match物件中。

1)使用group(N)方式返回對應的分組,1-N對應的是分組,0返回整個匹配的字串。

2)如果使用了命名分組,可以使用group(‘name’)的方式取分組。

3)也可以使用groups()返回所有組。

4)使用groupdict返回所有命名的分組。

Matcher.group()

matcher.groups()返回的是二元組。

Matcher.groupdict()字典。

import re
s = '''bottle\nbag\nbig\napple'''
for i,c in enumerate(s,1):
    print((i-1,c),end='\n' if i%8==0 else ' ')
print()
regex = re.compile('(b\w+)')
result = regex.match(s)
print(type(result))
print(1,'match',result.groups())
result =regex.search(s,1)
print(2,'search',result.groups())
regex = re.compile('(b\w+)\n(?P<name2>b\w+)\n(?P<name3>b\w+)')
result = regex.match(s)
print(3,'match',result)
print(4,result.group(3),result.group(2),result.group(1))
print(5,result.group(0).encode())
print(6,result.group('name2'),result.group('name3'))
print(6,result.groups())
print(7,result.groupdict())

result = regex.findall(s)
for x in result:
    print(8,type(x),x)

regex = re.compile('(?P<head>b\w+)')
result = regex.finditer(s)
for x in result:
    print(9,type(x),x,x.group(),x.group('head'))

(0, 'b') (1, 'o') (2, 't') (3, 't') (4, 'l') (5, 'e') (6, '\n') (7, 'b')

(8, 'a') (9, 'g') (10, '\n') (11, 'b') (12, 'i') (13, 'g') (14, '\n') (15, 'a')

(16, 'p') (17, 'p') (18, 'l') (19, 'e')

<class '_sre.SRE_Match'>

1 match ('bottle',)

2 search ('bag',)

3 match <_sre.SRE_Match object; span=(0, 14), match='bottle\nbag\nbig'>

4 big bag bottle

5 b'bottle\nbag\nbig'

6 bag big

6 ('bottle', 'bag', 'big')

7 {'name2': 'bag', 'name3': 'big'}

8 <class 'tuple'> ('bottle', 'bag', 'big')

9 <class '_sre.SRE_Match'> <_sre.SRE_Match object; span=(0, 6), match='bottle'> bottle bottle

9 <class '_sre.SRE_Match'> <_sre.SRE_Match object; span=(7, 10), match='bag'> bag bag

9 <class '_sre.SRE_Match'> <_sre.SRE_Match object; span=(11, 14), match='big'> big big

8、練習題:

1)判斷郵箱地址。

\w+[-.\w]*@[\w-]+(\.[\w-]+)+

2)html提取:

<[^<>]+>(.*)<^<>+>

3)URL提取。

(\w+)://([^\s]+)

4)身份驗證

身份證驗證需要使用計算公式,最嚴格的應該是實名驗證。

\d{17}[0-9xX]|\d{15}

5)單詞統計利用makekey等進行查詢。