24re

 

正則表達式

REregular expressionregexregexp

是文本處理極爲重要的技術,用它可以對字符串按照某種規則進行檢索、替換;

1970年,unix之父ken thompson將正則表達式引入到unix文本編輯器edgrep命令中,由此正則表達式普及開來;

1980年後,perl語言對henry spencer編寫的庫,擴展了很多新的特性;

1997年開始,philip hazel開發出了perl compatible regular expressions,它被phphttpd等工具採用;

RE應用極爲廣泛,shell中處理文本的命令,各種高級編程語言都支持RE

 

https://www.w3cschool.cn/regex_rmjc/

regester.NET軟件;

 

分類:

BRE,基本正則表達式,grepsedvi等軟件支持,vim有擴展;

ERE,擴展正則表達式,egrepgrep -Esed -r等;

PCRE,幾乎所有高級語言都是PCRE的方言或變種,python1.6開始使用SRE正則表達式引擎,可以認爲是PCRE的子集,見模塊re

 

基本語法:

meta character,元字符:

.,匹配除換行符外任意一個字符;

[abc],字符集合,只能表示一個字符位置,匹配除去集合內字符的任意一個字符;

[^abc],字符集合,只能表示一個字符位置,匹配除去集合內字符的任意一個字符;

[a-z],字符範圍,也是個集合,表示一個字符位置,匹配所包含的任意一個字符,常用[a-z][0-9]

[^a-z],字符範圍,也是個集合,表示一個字符位置,匹配除去集合內字符的任意一個字符;

\bboundary邊界,匹配單詞的邊界,例:\bb在文本中找到單詞中b開頭的b字符;

\B,不匹配單詞的邊界,例:t\B,包含t的單詞但不以t結尾的t字符;例:\Bb,不以b開頭的含有b的單詞,如able

\d[0-9]匹配1位數字;

\D[^0-9]匹配1位非數字;

\sseparator分隔符,匹配1位空白字符,包括換行符、製表符、空格;

\S,匹配1位非空白字符;

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

\W,匹配\w之外的字符;

 

單行模式:

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

^表示整個字符串的開頭;

$整個字符串的結尾;

 

多行模式:

.可以匹配除換行符之外的字符,換行符就不算了;

^表示行首,整個字符串的開始,開始指的是\n之後緊接着的下一個字符;

$表示行尾,整個字符串的結尾,結尾指的是\n之前緊接着的字符;

注:

win的換行符爲\r\n,在使用regester時要注意,\r?$

RE匹配unicode字符,空白分割的整體都按單詞算,如abe電話18621761169

 

例:e\r$,匹配文本abe

例:

1.jpg

注:單行模式&多行模式;

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重複nm次;e\w{0,1}等價於e\w?e'w{1,10}單詞中有e,至少1個至多10個非空白字符;

 

x|y,匹配xy

 

捕獲:

(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)oodood前一定有f(?<=t)akeake前一定有t出現;

 

負向零寬斷言:

(?!exp),零寬度負預測先行斷言,斷言exp一定不會出現在右側,即斷言後面一定不是exp

(?<!exp),零寬度負回顧後發斷言,斷言exp一定不能出現在左側,即斷言前面一定不能是exp;例:(?<!f)oooo前面不是f(?<!f)oo(?!k)oo前面不是f,後面不是k

 

注:

零寬斷言中的exp爲常值,不可以寫正則;

 

註釋:

(?#comment),如(?<!f)oo(?!d)(?#test)

 

注:

斷言不捕獲,也不匹配,不佔分組;

分組和捕獲是同一個意思,能用簡單表達式,就不用複雜的表達式;

 

例:

2.jpg

3.jpg

 

例:

\ba\w+|\bb\w+ --> \b(a|b)\w+ -->\b(?:a|b)\w+

 

例:

4.jpg

5.jpg

6.jpg

 

 

 

貪婪與非貪婪:

默認是貪婪模式,即儘量多匹配更長的字符串;

非貪婪,在重複的符號後加上一個?,就儘量的少匹配了;

 

*?,匹配任意項,但儘可能少重複;

+?,匹配至少1次,但儘可能少重複;

??,匹配0次或1次,但儘可能少重複;

{n,}?,匹配至少n次,但儘可能少重複;

{n,m}?,匹配至少n次,至多m次,但儘可能少重複;

 

引擎選項:

IgnoreCase,匹配時忽略大小寫,re.Ire.IGNORECASE;寫代碼時,找到的字串要轉爲小寫或大寫才能成爲dictkey

Singleline,單行模式,可以匹配所有字符,包括\nre.Sre.DOTALL

Multiline,多行模式,^行首,$行尾,re.Mre.MULTILINE

IgnorePatternWhitespace,忽略表達式中的空白字符,如果要使用空白字符用轉義,#可以用來作註釋,re.Xre.VERBOSE,一般不用此項;

 

例:

7.jpg

8.jpg

9.jpg

10.jpg

11.jpg

f\w+?t,常用;

 

例:

12.jpg

 

注:

http狀態碼分析;

引用(盜鏈);

User-Agentrobotspider);

PVUV

 

 

 

pythonre

re.Mre.MULTILINE,多行模式;

re.Sre.DOTALL,單行模式;

re.Ire.IGNORECASE,忽略大小寫;

re.Xre.VERBOSE,忽略表達式中的空白字符,不用此項;

|,位或,開啓多種選項,如re.M | re.I00010010010010001 | 0 = 11 | 1 = 10 | 1 = 10 | 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.Mre.Sre.Ire.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系列(findallfinditer):

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可以是stringbytesfunction

regex.sub(repl,string,count=0),使用pattern對字符串string進行匹配,對匹配項使用repl替換,repl可以是stringbytesfunction

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、手機號碼;

13.jpg

14.jpg

 

2、座機;

15.jpg

 

3、匹配0-999之間的任意數字;

\d{1,3}

一位數,\d

一位數或二位數,^[1-9]?\d\r?$   #\r?僅在win下使用

^[1-9]?\d\d?\r?$

^(?:[1-9]\d\d?|\d)\r?$

 

4ipv4點分四段;

(?:\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://的鏈接,且文件類型是gzxz的文件名;

^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]   #最常用

 

11word count

16.jpg

17.jpg

18.jpg

注:

\b\w+\b

[^\.\(\)\[\]]+

 

19.jpg

 

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)

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章