正則表達式php
RE,regular expression,regex,regexp;html
是文本處理極爲重要的技術,用它能夠對字符串按照某種規則進行檢索、替換;python
1970年,unix之父ken thompson將正則表達式引入到unix文本編輯器ed和grep命令中,由此正則表達式普及開來;正則表達式
1980年後,perl語言對henry spencer編寫的庫,擴展了不少新的特性;shell
1997年開始,philip hazel開發出了perl compatible regular expressions,它被php和httpd等工具採用;express
RE應用極爲普遍,shell中處理文本的命令,各類高級編程語言都支持RE;編程
https://www.w3cschool.cn/regex_rmjc/vim
regester,.NET軟件;app
分類:socket
BRE,基本正則表達式,grep、sed、vi等軟件支持,vim有擴展;
ERE,擴展正則表達式,egrep或grep -E,sed -r等;
PCRE,幾乎全部高級語言都是PCRE的方言或變種,python從1.6開始使用SRE正則表達式引擎,能夠認爲是PCRE的子集,見模塊re;
基本語法:
meta character,元字符:
.,匹配除換行符外任意一個字符;
[abc],字符集合,只能表示一個字符位置,匹配除去集合內字符的任意一個字符;
[^abc],字符集合,只能表示一個字符位置,匹配除去集合內字符的任意一個字符;
[a-z],字符範圍,也是個集合,表示一個字符位置,匹配所包含的任意一個字符,經常使用[a-z]、[0-9];
[^a-z],字符範圍,也是個集合,表示一個字符位置,匹配除去集合內字符的任意一個字符;
\b,boundary邊界,匹配單詞的邊界,例:\bb在文本中找到單詞中b開頭的b字符;
\B,不匹配單詞的邊界,例:t\B,包含t的單詞但不以t結尾的t字符;例:\Bb,不以b開頭的含有b的單詞,如able;
\d,[0-9]匹配1位數字;
\D,[^0-9]匹配1位非數字;
\s,separator分隔符,匹配1位空白字符,包括換行符、製表符、空格;
\S,匹配1位非空白字符;
\w,匹配[a-zA-Z0-9],包括中文的字;
\W,匹配\w以外的字符;
單行模式:
.能夠匹配全部字符,包括換行符;
^表示整個字符串的開頭;
$整個字符串的結尾;
多行模式:
.能夠匹配除換行符以外的字符,換行符就不算了;
^表示行首,整個字符串的開始,開始指的是\n以後緊接着的下一個字符;
$表示行尾,整個字符串的結尾,結尾指的是\n以前緊接着的字符;
注:
win的換行符爲\r\n,在使用regester時要注意,\r?$;
RE匹配unicode字符,空白分割的總體都按單詞算,如abe電話18621761169;
例:e\r$,匹配文本abe;
例:
注:單行模式&多行模式;
In [4]: s = '''very very happy
...: harry key
...: :
...: '''
In [11]: str1=re.compile('y$',re.M)
In [12]: str1.findall(s)
Out[12]: ['y', 'y']
轉義:
凡是在RE中有特殊意義的符號,若是想使用它的本意,用\,反斜槓自身用\\;
\r、\n仍是轉義後表明回車、換行;
重複:
*,表示前面的RE會重複0次或屢次;e\w*,單詞中有e,後面非空白字符;
+,表示前面的RE重複至少1次;e\w+,單詞中有e,後面至少一個非空白字符;
?,表示前面的RE重複0次或1次;e\w?,單詞中有e,後面至多有一個非空白字符;
{n},表示前面的RE重複n次;e\w{1},單詞中有e,後面只能有一個非空白字符;
{n,},表示前面的RE重複至少n次;e\w{1,}等價於e\w+;e\w{0,}等價於e\w*;
{n,m},表示前面的RE重複n到m次;e\w{0,1}等價於e\w?;e'w{1,10}單詞中有e,至少1個至多10個非空白字符;
x|y,匹配x或y;
捕獲:
(pattern),使用小括號指定一個子表達式,也叫分組,捕獲後會自動分配組號,組號從1開始,能夠改變優先級;
\數字,匹配對應的分組;
(?:pattern),若是僅僅爲了改變優先級,就不須要捕獲分組;
(?<name>exp)或(?'name'exp),命名分組,分組捕獲,但可經過name訪問分組,很好用,可與dict對應;python的命名分組語法特殊要加P,格式:(?P<name>exp);
零寬斷言:
(?=exp),零寬度正預測先行斷言,斷言exp必定在匹配的右邊出現,即斷言後面必定跟個exp;例:f(?=oo),f後必定有oo出現;
(?<=exp),零寬度正回顧後發斷言,斷言exp必定在匹配的左邊出現,即前面必定有個exp前綴;例:(?<=f)ood,ood前必定有f,(?<=t)ake,ake前必定有t出現;
負向零寬斷言:
(?!exp),零寬度負預測先行斷言,斷言exp必定不會出如今右側,即斷言後面必定不是exp;
(?<!exp),零寬度負回顧後發斷言,斷言exp必定不能出如今左側,即斷言前面必定不能是exp;例:(?<!f)oo,oo前面不是f,(?<!f)oo(?!k),oo前面不是f,後面不是k;
注:
零寬斷言中的exp爲常值,不能夠寫正則;
註釋:
(?#comment),如(?<!f)oo(?!d)(?#test);
注:
斷言不捕獲,也不匹配,不佔分組;
分組和捕獲是同一個意思,能用簡單表達式,就不用複雜的表達式;
例:
例:
\ba\w+|\bb\w+ --> \b(a|b)\w+ -->\b(?:a|b)\w+
例:
貪婪與非貪婪:
默認是貪婪模式,即儘可能多匹配更長的字符串;
非貪婪,在重複的符號後加上一個?,就儘可能的少匹配了;
*?,匹配任意項,但儘量少重複;
+?,匹配至少1次,但儘量少重複;
??,匹配0次或1次,但儘量少重複;
{n,}?,匹配至少n次,但儘量少重複;
{n,m}?,匹配至少n次,至多m次,但儘量少重複;
引擎選項:
IgnoreCase,匹配時忽略大小寫,re.I或re.IGNORECASE;寫代碼時,找到的字串要轉爲小寫或大寫才能成爲dict的key;
Singleline,單行模式,能夠匹配全部字符,包括\n,re.S或re.DOTALL;
Multiline,多行模式,^行首,$行尾,re.M或re.MULTILINE;
IgnorePatternWhitespace,忽略表達式中的空白字符,若是要使用空白字符用轉義,#能夠用來做註釋,re.X或re.VERBOSE,通常不用此項;
例:
f\w+?t,經常使用;
例:
注:
http狀態碼分析;
引用(盜鏈);
User-Agent(robot,spider);
PV,UV;
python的re:
re.M,re.MULTILINE,多行模式;
re.S,re.DOTALL,單行模式;
re.I,re.IGNORECASE,忽略大小寫;
re.X,re.VERBOSE,忽略表達式中的空白字符,不用此項;
|,位或,開啓多種選項,如re.M | re.I,0001,0010,0100,1000,1 | 0 = 1,1 | 1 = 1,0 | 1 = 1,0 | 0 = 0,兩個中有一個爲1則爲1;
re中的方法:
編譯:
re.compile(pattern,flags=0)-->regex正則表達式對象,
Compile a regular expression pattern, returning a pattern object.
爲提升效率,正則表達式須要被編譯,編譯後的結果被保存,下次使用一樣pattern時,就不須要再次編譯;re的其它方法爲了提升效率都調用了compile()編譯方法;
pattern,即正則表達式字符串,
flags,編譯模式,即re.M,re.S,re.I,re.X;
返回正則表達式對象regex;
match系列(match,search,fullmatch):
re.match(pattern,string,flags=0)-->match object,從字符串開頭匹配,找到第1個當即返回,返回match對象;
regex.match(string[,pos[,endpos]])-->match object,可重設開始位置和結束位置,返回match對象;
re.search(pattern,string,flags=0)-->match object,從頭搜索,直到第1個匹配,返回match對象;
regex.search(string[,pos[,endpos]])-->match object,可重設開始位置和結束位置,返回match對象;
re.fullmatch(pattern,string,flags=0)-->match object,整個字符串和正則表達式匹配;
regex.fullmatch(string[,pos[,endpos]])-->match object,整個字符串和正則表達式匹配;
find系列(findall,finditer):
re.findall(pattern,string,flags=0)-->list,對整個字符串,從左至右匹配,返回全部匹配項的列表;
regex.findall(string[,pos[,endpos]])-->list,對整個字符串,從左至右匹配,返回全部匹配項的列表;
re.finditer(pattern,string,flags=0)-->iterator-->match object,對整個字符串從左至右匹配,返回全部匹配項,返回迭代器,注意每次迭代返回的是match object;
regex.finditer(string[,pos[,endpos]])-->iterator-->match object,對整個字符串從左至右匹配,返回全部匹配項,返回迭代器,注意每次迭代返回的是match object;
匹配替換:
re.sub(pattern,repl,string,count=0,flags=0),
使用pattern對字符串string進行匹配,對匹配項使用repl替換,repl能夠是string、bytes、function;
regex.sub(repl,string,count=0),使用pattern對字符串string進行匹配,對匹配項使用repl替換,repl能夠是string、bytes、function;
re.subn(pattern,repl,string,count=0,flags=0)-->2-tuple,同sub,返回一個元組,(new_string,number_of_subs_made);
regex.subn(repl,string,count=0)-->2-tuple,同sub,返回一個元組,(new_string,number_of_subs_made);
分割字符串:
字符串的分割函數太難用,不能指定多個字符進行分割,str.split();
re.split(pattern,string,maxsplit=0,flags=0),正則的分割;
分組:
pattern加上小括號,捕獲的數據被放到了group組中;
只有match object,才能用group相關的方法,groups(),group(),groupdict();
match(),search()返回match object;
findall()返回字符串列表,不能用group相關的方法;
finditer(),返回一個個的match object;
python中使用了分組,若有匹配的結果,會在match object中;
group(num),使用此方式返回對應分組,1-num是對應的分組,分組編號從1開始,0返回整個匹配的字符串;
group('name'),若是使用了命名分組,可用此方式取分組;
groups(),返回全部組,各分組組成tuple;
groupdict(),返回全部命名分組;
例:
折行處理:
s = '''bottle\nbag\nbig\napple'''
for x in enumerate(s):
if x[0] % 8 == 0:
print()
print(x,end=' ')
print('\n')
例:
import re
s = '0123abc'
matcher = re.match('\d', s) #查看源碼可知,查找以前會事先編譯,python中,不想給別人用的方法名或變量名,前面加_,如_compile();錨定索引0,若開始處沒找到,則再也不找,找不到返回None,找到返回match object
print(type(matcher))
print(matcher)
print(matcher.span()) #記錄着從哪開始到哪結束
print(matcher.start()) #匹配的索引
print(matcher.end())
regex = re.compile('\d')
matcher = regex.match(s)
print(type(matcher))
print(matcher)
regex = re.compile('[ab]')
matcher = regex.match(s,4) #指定開始位置
print(type(matcher))
print(matcher)
輸出:
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 1), match='0'>
(0, 1)
0
1
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(0, 1), match='0'>
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(4, 5), match='a'>
例:
import re
s = '0123abc'
matcher = re.search('[ab]',s)
print(type(matcher))
print(matcher)
regex = re.compile('[ab]')
matcher = regex.search(s)
print(type(matcher))
print(matcher)
matcher = re.fullmatch('\w+',s)
print(matcher)
regex = re.compile('\w+')
matcher = regex.fullmatch(s)
print(matcher)
matcher = regex.fullmatch(s,4,6)
print(matcher)
輸出:
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(4, 5), match='a'>
<class '_sre.SRE_Match'>
<_sre.SRE_Match object; span=(4, 5), match='a'>
<_sre.SRE_Match object; span=(0, 7), match='0123abc'>
<_sre.SRE_Match object; span=(0, 7), match='0123abc'>
<_sre.SRE_Match object; span=(4, 6), match='ab'>
例:
import re
s = '''bottle\nbag\nbig\napple'''
regex = re.compile('[ab]')
matcher = regex.findall(s)
print(matcher)
matcher = regex.finditer(s)
print(type(matcher))
print(matcher)
for i in matcher:
print(i)
輸出:
['b', 'b', 'a', 'b', 'a']
<class 'callable_iterator'>
<callable_iterator object at 0x7f63d4987b00> #用next(matcher)或for loop
<_sre.SRE_Match object; span=(0, 1), match='b'>
<_sre.SRE_Match object; span=(7, 8), match='b'>
<_sre.SRE_Match object; span=(8, 9), match='a'>
<_sre.SRE_Match object; span=(11, 12), match='b'>
<_sre.SRE_Match object; span=(15, 16), match='a'>
例:
import re
s = '''os.path([path])'''
regex = re.compile('[\.]')
newstr = regex.sub(' ',s)
print(newstr)
newstr = regex.subn(' ',s,3)
print(newstr)
輸出:
os path([path])
('os path([path])', 1)
例:
import re
s = ''' 01 bottle
02 bag
03 big1
100 able
'''
result = re.split('[\s\d]+',s)
print(result)
regex = re.compile('^[\s\d]+',re.M)
result = regex.split(s)
print(result)
regex = re.compile('\s+|(?<!\w)\d+')
result = regex.split(s)
print(result)
regex = re.compile('\s+\d+\s+')
result = regex.split(s)
print(result)
例:
import re
s = '''bottle\nbig\nbag1\nable'''
regex = re.compile('(b\wg)')
matcher = regex.search(s)
print(matcher.groups())
print(matcher.group(0))
regex = re.compile('(b\w+)(e)')
matchers = regex.finditer(s)
for matcher in matchers:
print(matcher)
print(matcher.groups())
regex = re.compile('b(\w+)(?P<tail>e)')
matchers = regex.finditer(s)
for matcher in matchers:
print(matcher.groups())
print(matcher.groupdict('tail'))
輸出:
('big',)
big
<_sre.SRE_Match object; span=(0, 6), match='bottle'>
('bottl', 'e')
<_sre.SRE_Match object; span=(17, 20), match='ble'>
('bl', 'e')
('ottl', 'e')
{'tail': 'e'}
('l', 'e')
{'tail': 'e'}
習題:
1、手機號碼;
2、座機;
3、匹配0-999之間的任意數字;
\d{1,3}
一位數,\d
一位數或二位數,^[1-9]?\d\r?$ #\r?僅在win下使用
^[1-9]?\d\d?\r?$
^(?:[1-9]\d\d?|\d)\r?$
4、ipv4點分四段;
(?:\d{1,3}\.){3}\d{1,3}
(?:(?:\d{1,2}|[0-2]\d{2})\.){3}(?:\d{1,2}|[0-2]\d{2}) #解決超出200的問題,仍有256的問題
方1:
In [8]: import socket
In [9]: new = socket.inet_aton('192.168.05.001') #有異常則非ipv4地址
In [10]: print(new,socket.inet_ntoa(new))
b'\xc0\xa8\x05\x01' 192.168.5.1
方2:
(?:(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d\d?|2[0-4]\d|25[0-5])
5、含有ftp://的連接,且文件類型是gz或xz的文件名;
^ftp://.*/(.+?(?:.gz|.xz))\r?$ #.*貪婪,.+?非貪婪
(?<=ftp.*/)[^/]*\.(?:gz|xz) #直接取到文件名,零寬斷言中的exp表達式爲常值,不能寫正則
(?<=ftp)(?:(?:.*/)([^/]*\.(?:gz|xz)))
6、匹配郵箱地址;
(?:^\w[\w\.-]*)@(?:\w[\w\.-]*\.[a-zA-Z]+)
7、
(1)匹配html標記內的內容;
<a href="www.magedu.com" target='_blank'>馬哥教育</a>
(?<=>)\w+(?=<)
(2)<a href="www.magedu.com" target='_blank'>馬哥<br>教育</a>
<a[^<>]*>(.+)</a>
(3)取href中的網址;
<a[^<>]*href="([^<>]+?)"
8、匹配url;
(?:\w+)://[\S]+
(?:\w+)://[^\s]+
注:
url中不能有空格或空白,若有要用url編碼處理;
9、匹配×××(15位,18位);
\d{17}[xX\d]|\d{15}
10、強密碼,10-15位,包含大寫字母、小寫字母、數字、下劃線,四種類型同時出現纔是合格的強密碼;
\w{10,15},弱密碼;
判斷前後:
\W
{10,15}
_ #有_爲最強密碼
[A-Z]
\d
[a-z] #最經常使用
11、word count
注:
\b\w+\b
[^\.\(\)\[\]]+
import re
from collections import defaultdict
regex = re.compile('[^-\w]+')
def wordcount(path):
d = defaultdict(lambda: 0)
with open(path) as f:
for line in f:
for sub in regex.split(line):
if len(sub) >= 1:
d[sub.lower()] += 1
return d
x = 0
for i in sorted(wordcount('/home/python/magedu/projects/cmdb/example.txt').items(),\
key=lambda i:i[1],reverse=True):
if x < 10:
print(i)
x += 1
輸出:
('path', 166)
('if', 79)
('the', 74)
('a', 57)
('p', 57)
('return', 56)
('is', 52)
('and', 50)
('os', 47)
('in', 44)