python圣斗士(十七):令人欲罢不能的正则
什么是正則
字符串是編程時涉及到的最多的一種數據結構,對字符串進行操作的需求幾乎無處不在。比如判斷一個字符串是否是合法的Email地址,雖然可以編程提取@前后的子串,再分別判斷是否是單詞和域名,但這樣做不但麻煩,而且代碼難以復用。
正則表達式是一種用來匹配字符串的強有力的武器。它的設計思想是用一種描述性的語言來給字符串定義一個規則,凡是符合規則的字符串,我們就認為它“匹配”了,否則,該字符串就是不合法的。
所以我們判斷一個字符串是否是合法的Email的方法是:
創建一個匹配Email的正則表達式;用該正則表達式去匹配用戶的輸入來判斷是否合法。因為正則表達式也是用字符串表示的,所以,我們要首先了解如何用字符來描述字符。
在正則表達式中,如果直接給出字符,就是精確匹配。用\d可以匹配一個數字,\w可以匹配一個字母或數字,所以:
'00\d'可以匹配'007',但無法匹配'00A';'\d\d\d'可以匹配'010';'\w\w\d'可以匹配'py3';.可以匹配任意字符,所以:
'py.'可以匹配'pyc'、'pyo'、'py!'等等。要匹配變長的字符,在正則表達式中,用*表示任意個字符(包括0個),用+表示至少一個字符,用?表示0個或1個字符,用{n}表示n個字符,用{n,m}表示n-m個字符:
來看一個復雜的例子:\d{3}\s+\d{3,8}。
我們來從左到右解讀一下:
\d{3}表示匹配3個數字,例如'010';\s可以匹配一個空格(也包括Tab等空白符),所以\s+表示至少有一個空格,例如匹配' ',' '等;\d{3,8}表示3-8個數字,例如'1234567'。綜合起來,上面的正則表達式可以匹配以任意個空格隔開的帶區號的電話號碼。
如果要匹配’010-12345’這樣的號碼呢?由于’-‘是特殊字符,在正則表達式中,要用’\’轉義,所以,上面的正則是\d{3}-\d{3,8}。
但是,仍然無法匹配’010 - 12345’,因為帶有空格。所以我們需要更復雜的匹配方式。
正則基礎語法:
在正則表達式中用約定的字符串和符號作為匹配的類型和規則,這些符號就叫做元字符,下列是常見的一些正則匹配元字符:
. 匹配單個任意字符,默認不匹配換行符,除非在匹配條件末尾加上re.S選項。
* 匹配任意個任意字符
^ 匹配以某個字符開頭的
?匹配單個或0個任意字符
+ 匹配單個或多個字符
[] 匹配括號中的單個字符
\ 轉義符
\W 非單詞字符
\w 單詞字符[0-9a-zA-Z]
\D 非數字
\d純數字
\s空格
\S匹配非空白字符)
\b:\bthe 匹配任何以the開始的字符串;\bthe\b 匹配the本身
\B:邊界匹配 \Bthe 包含the但不以the為開始的字符串
參考地址:http://icybamboo.iteye.com/blog/585291
python的正則
python中關于正則的模塊是re
- 常用方法:
為什么要加r:r是raw(原始)的意思。因為在表示字符串中有一些轉義符,如表示回車’\n’。如果要表示\表需要寫為’\\’。但如果我就是需要表示一個’\’+’n’,不用r方式要寫為:’\\n’。但使用r方式則為r’\n’這樣清晰多了。所以一般情況下我們都會加上r。
- 生成正則對象使用:
p=re.compile(r’abc’) 編譯生成一個正則對象
p=re.compile(r’G’,re.I)
p.findall(‘aaabcacac’) 調用方法
//[‘abc’]
- 正則標記
在上面的代碼中,我們注意到第二行里面在正則匹配式后面還跟著一個re.I,這個附加條件就成為正則標記,這里的意思是忽略大小寫。如我們所見,正則標記就是為了更好地靈活匹配而誕生的,常見的正則標記如下:
re.S 使得.匹配包括換行符在內的任何字符
re.I 忽略大小寫
re.M:多行匹配,影響^和$
re.X:啟用詳細的正則表達式
re.L:支持當前的語言(區域)設置
re.A:使得轉義符號如\w,\b,\s,\d只能匹配ASCII字符正則分組
除了簡單地判斷是否匹配之外,正則表達式還有提取子串的強大功能。用()表示的就是要提取的分組(Group)。比如:
^(\d{3})-(\d{3,8})$分別定義了兩個組,可以直接從匹配的字符串中提取出區號和本地號碼:
m = re.match(r’^(\d{3})-(\d{3,8})$’, ‘010-12345’)
m
//<_sre.SRE_Match object at 0x1026fb3e8>
m.group(0)
‘010-12345’
m.group(1)
//’010’
m.group(2)
//’12345’
如果正則表達式中定義了組,就可以在Match對象上用group()方法提取出子串來。
注意到group(0)永遠是原始字符串,group(1)、group(2)……表示第1、2、……個子串。
提取子串非常有用。來看一個更兇殘的例子:
t = ‘19:05:30’
m = re.match(r’^(0[0-9]|1[0-9]|2[0-3]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$’, t)
m.groups()
(‘19’, ‘05’, ‘30’)
這個正則表達式可以直接識別合法的時間。但是有些時候,用正則表達式也無法做到完全驗證,比如識別日期:
‘^(0[1-9]|1[0-2]|[0-9])-(0[1-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$’
對于’2-30’,’4-31’這樣的非法日期,用正則還是識別不了,或者說寫出來非常困難,這時就需要程序配合識別了。
- 貪婪匹配
最后需要特別指出的是,正則匹配默認是貪婪匹配,也就是匹配盡可能多的字符。舉例如下,匹配出數字后面的0:
re.match(r’^(\d+)(0*)$’, ‘102300’).groups()
(‘102300’, ”)
由于\d+采用貪婪匹配,直接把后面的0全部匹配了,結果0*只能匹配空字符串了。
必須讓\d+采用非貪婪匹配(也就是盡可能少匹配),才能把后面的0匹配出來,加個?就可以讓\d+采用非貪婪匹配:
re.match(r’^(\d+?)(0*)$’, ‘102300’).groups()
(‘1023’, ‘00’)
范例:
匹配IP地址:
re.search(r’(([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).){3}([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])’,’192.168.1.256’)
總結
以上是生活随笔為你收集整理的python圣斗士(十七):令人欲罢不能的正则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 暴力递归到动态规划
- 下一篇: 两个cgi的莫名其妙的core dump