<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Python基礎(chǔ)】Python正則表達(dá)式入門到入魔

          共 20735字,需瀏覽 42分鐘

           ·

          2021-02-06 16:36


          關(guān)于正則表達(dá)式,很多人認(rèn)為,使用的時候查詢下就可以,沒必要深入學(xué)習(xí),但是知識與應(yīng)用永遠(yuǎn)都是螺旋辯證的關(guān)系,有需要查詢也無可厚非,但是先掌握知識,可以讓應(yīng)用更創(chuàng)新,更深入,超越他人,必須要先掌握大量的深刻的知識。

          如果正則學(xué)的好,你會發(fā)現(xiàn)它功能強(qiáng)大、妙用無窮。對于很多實(shí)際工作來講,正則表達(dá)式簡直是靈丹妙藥,能夠成百倍地提高開發(fā)效率和程序質(zhì)量。

          但是學(xué)習(xí)正則并非易事:知識點(diǎn)瑣碎、記憶點(diǎn)多、符號亂,難記憶、難描述、廣而深且,為此,我做了一個全面的整理,希望能幫助到大家。

          正則表達(dá)式是一個復(fù)雜的主題,因此本文非常長,作者能力有限,錯誤之處,懇請指正,為了方便閱讀,先看文章目錄:


          一、起源發(fā)展

          ? 1、20世紀(jì)40年代

          ??2、20世紀(jì)50年代

          ??3、20世紀(jì)60年代

          ??4、20世紀(jì)80年代

          二、學(xué)習(xí)資料

          ??1、re模塊官方文檔(中文版)

          ??2、Python內(nèi)置模塊

          ??3、re模塊庫源代碼

          ? 4、正則表達(dá)HOWTO

          ??5、學(xué)習(xí)網(wǎng)站

          三、re模塊簡介

          四、語法原理

          ??1、基本元字符

          ??2、數(shù)量元字符

          ??3、位置元字符

          ??4、特殊元字符

          ??5、前后查找

          ??6、回溯引用

          ??7、大小寫轉(zhuǎn)換

          五、常量模塊

          ??1、IGNORECASE

          ??2、ASCII

          ??3、DOTALL

          ??4、MULTILINE

          ??5、VERBOSE

          ??6、LOCALE

          ??7、UNICODE

          ??8、DEBUG

          ??9、TEMPLATE

          ??10、常量總結(jié)

          六、函數(shù)模塊

          ??1、查找一個匹配項(xiàng)

          ?????1)search()

          ??? ?2match()

          ??? ?3fullmatch()

          ? 2、查找多個匹配項(xiàng)

          ???? 1)findall()

          ??? ?2)finditer()

          ??3、匹配項(xiàng)分割

          ??????1)split()

          ??4、匹配項(xiàng)替換

          ??? ?1)sub()

          ??? ?2)subn()

          ??5、編譯正則對象

          ??6、轉(zhuǎn)義函數(shù)

          ??7、緩存清除函數(shù)

          六、異常模塊



          一、起源發(fā)展

          我們在學(xué)習(xí)一門技術(shù)的時候有必要簡單的了解其起源與發(fā)展過程,這對學(xué)習(xí)知識有一定的幫助。

          1、20世紀(jì)40年代

          正則表達(dá)式最初的想法來自兩位神經(jīng)學(xué)家:沃爾特·皮茨與麥卡洛克,他們研究出了一種用數(shù)學(xué)方式來描述神經(jīng)網(wǎng)絡(luò)的模型。

          2、20世紀(jì)50年代

          一位名叫Stephen Kleene的數(shù)學(xué)科學(xué)家發(fā)表了一篇題目是《神經(jīng)網(wǎng)事件的表示法》的論文,利用稱之為正則集合的數(shù)學(xué)符號來描述此模型,引入了正則表達(dá)式的概念。正則表達(dá)式被作為用來描述其稱之為“正則集的代數(shù)”的一種表達(dá)式,因而采用了“正則表達(dá)式”這個術(shù)語。

          3、20世紀(jì)60年代

          C語言之父、UNIX之父肯·湯普森把這個“正則表達(dá)式”的理論成果用于做一些搜索算法的研究,他描述了一種正則表達(dá)式的編譯器,于是出現(xiàn)了應(yīng)該算是最早的正則表達(dá)式的編譯器qed(這也就成為后來的grep編輯器)。

          Unix使用正則之后,正則表達(dá)式不斷的發(fā)展壯大,然后大規(guī)模應(yīng)用于各種領(lǐng)域,根據(jù)這些領(lǐng)域各自的條件需要,又發(fā)展出了許多版本的正則表達(dá)式,出現(xiàn)了許多的分支。我們把這些分支叫做“流派”。

          4、20世紀(jì)80年代

          Perl語言誕生了,它綜合了其他的語言,用正則表達(dá)式作為基礎(chǔ),開創(chuàng)了一個新的流派,Perl流派。之后很多編程語言如:Python、Java、Ruby、.Net、PHP等等在設(shè)計(jì)正則式支持的時候都參考Perl正則表達(dá)式到這里我們也就知道為什么眾多編程語言的正則表達(dá)式基本一樣,因?yàn)樗麄兌紟煆腜erl。注:Perl語言是一種擅長處理文本的語言,Larry在1987年創(chuàng)建,Practical Extraction and Report Language,實(shí)用報(bào)表提取語言,但因晦澀語法和古怪符號不利于理解和記憶導(dǎo)致很多開發(fā)者并不喜歡。


          二、學(xué)習(xí)資料

          Python對正則表達(dá)式的支持,主要是re庫,這是一個Python的標(biāo)準(zhǔn)庫。也就是該庫是一個內(nèi)置模塊(Python大概300個內(nèi)置模塊),不需要額外的下載,使用的時候,直接 import re 加載即可。下面是一些常用的學(xué)習(xí)資料鏈接。

          1、re模塊官方文檔(中文版)

          https://docs.python.org/zh-cn/3.7/library/re.html

          2、Python內(nèi)置模塊

          https://docs.python.org/3/py-modindex.html#cap-r

          3、re模塊庫源代碼

          https://github.com/python/cpython/blob/3.8/Lib/re.py

          4、正則表達(dá)HOWTO

          https://docs.python.org/zh-cn/3.7/howto/regex.html#regex-howto ? ? ? ? ? ? ? ? ? ? ?

          5、學(xué)習(xí)網(wǎng)站

          https://www.runoob.com/python/python-reg-expressions.html

          ?

          三、re模塊簡介

          Python的re模塊主要定義了9個常量、12個函數(shù)、1個異常,下面先講一些基本原理后,慢慢介紹具體的函數(shù)用法。

          import?reprint(dir(re))['A',?'ASCII',?'DEBUG',?'DOTALL',?'I',?'IGNORECASE',?'L',?'LOCALE',?'M',?'MULTILINE',?'Match',?'Pattern',?'RegexFlag',?'S',?'Scanner',?'T',?'TEMPLATE',?'U',?'UNICODE',?'VERBOSE',?'X',?...,?'compile',?'copyreg',?'enum',?'error',?'escape',?'findall',?'finditer',?'fullmatch',?'functools',?'match',?'purge',?'search',?'split',?'sre_compile',?'sre_parse',?'sub',?'subn',?'template']
          ?

          四、語法原理

          完整的正則表達(dá)式由兩種字符構(gòu)成:特殊字符(元字符)和普通字符。元字符表示正則表達(dá)式功能的最小單位,如*?^?$?\d等

          1、基本元字符

          .

          在默認(rèn)模式,匹配除了換行的任意字符。如果指定了標(biāo)簽re.DOTALL,它將匹配包括換行符的任意字符。

          import?re#除了換行符\n,其他都匹配出來了re.findall(r'.','小伍哥\n真帥')['小',?'伍',?'哥',?'真',?'帥']
          #加了條件,都匹配出來了re.findall(r'.','小伍哥\n真帥',re.DOTALL)['小',?'伍',?'哥',?'\n',?'真',?'帥']
          #匹配'd...c',三個點(diǎn)表示中間三個字符re.findall(r'd...c','abd9匹配cdd')['d9匹配c']

          \

          轉(zhuǎn)義特殊字符(允許你匹配'*','?', 或者此類其他特殊字符),或者表示一個特殊序列;如果你沒有使用原始字符串(r'raw')來表達(dá)樣式,要牢記Python也使用反斜杠\作為轉(zhuǎn)義序列;如果轉(zhuǎn)義序列不被Python的分析器識別,反斜杠和字符才能出現(xiàn)在字符串中。如果Python可以識別這個序列,那么反斜杠就應(yīng)該重復(fù)兩次。這將導(dǎo)致理解障礙,所以高度推薦,就算是最簡單的表達(dá)式,也要使用原始字符串。

          []

          用于表示一個字符集合。在一個集合中:

          1)字符可以單獨(dú)列出,比如[amk]匹配'a','m',或者'k'。

          re.findall(r'[小帥]','小伍哥真帥')['小',?'帥']

          2)可以表示字符范圍,通過用'-'將兩個字符連起來。比如[a-z]將匹配任何小寫ASCII字符,[0-5][0-9]將匹配從00到59的兩位數(shù)字,[0-9A-Fa-f]將匹配任何十六進(jìn)制數(shù)位。如果-進(jìn)行了轉(zhuǎn)義(比如[a\-z])或者它的位置在首位或者末尾(如[-a]或[a-]),它就只表示普通字符'-'。

          #匹配從00到59的兩位數(shù)字
          re.findall(r'[0-5][0-9]','012234456789')['01',?'22',?'34',?'45']

          3)特殊字符在集合中,失去它的特殊含義。如[(+*)]只會匹配這幾個文法字符'(', '+', '*', 或')'。

          4)字符類如\w或者\(yùn)S(如下定義) 在集合內(nèi)可以接受,它們可以匹配的字符由ASCII或LOCALE模式?jīng)Q定。

          5)不在集合范圍內(nèi)的字符可以通過取反來進(jìn)行匹配。如果集合首字符是'^',所有不在集合內(nèi)的字符將會被匹配,比如[^5]?將匹配所有字符,除了'5',[^^]將匹配所有字符,除了'^'.^如果不在集合首位,就沒有特殊含義。

          #除了TM,都匹配出來
          re.findall(r'[^TM]','小伍哥真TM帥')['小', '伍', '哥', '真', '帥']

          |

          A|B,A和B可以是任意正則表達(dá)式,創(chuàng)建一個正則表達(dá)式,匹配A或者B.,任意個正則表達(dá)式可以用'|'連接。它也可以在組合(見下列)內(nèi)使用。掃描目標(biāo)字符串時,'|'分隔開的正則樣式從左到右進(jìn)行匹配。當(dāng)一個樣式完全匹配時,這個分支就被接受。意思就是,一旦A匹配成功,B就不再進(jìn)行匹配,即便它能產(chǎn)生一個更好的匹配。或者說'|'操作符絕不貪婪。如果要匹配'|'字符,使用\|,或者把它包含在字符集里,比如[|]。

          -

          可以表示字符范圍,通過用'-'將兩個字符連起來。比如[a-z]將匹配任何小寫ASCII字符,[0-5][0-9]將匹配從00到59的兩位數(shù)字,[0-9A-Fa-f]將匹配任何十六進(jìn)制數(shù)位。

          re.findall(r'[1-3]','012234456789')#查找所有1-3之間的自然數(shù)['1', '2', '2', '3']

          ()?

          匹配器整體為一個原子,即模式單元可以理解為多個原子組成的大原子

          ?

          2、數(shù)量元字符

          *

          對它前面的正則式匹配0到任意次重復(fù),ab*會匹配?'a','ab','abbb...',注意只重復(fù)b,盡量多的匹配字符串

          re.findall(r'ab*','ababbbbaabbcaacb')['ab',?'abbbb',?'a',?'abb',?'a',?'a']#重復(fù).0到任意次,.有代表任意字符,所有d.*c能匹配dc之間包含任意字符re.findall(r'd.*c','abd9我愛學(xué)習(xí)cdd')['d9我愛學(xué)習(xí)c']

          +

          對它前面的正則式匹配1到任意次重復(fù)。ab+會匹配'a'后面跟隨1個以上到任意個'b',它不會匹配'a'。

          re.findall(r'ab+','ababbbbaabbcaacb')['ab',?'abbbb',?'abb']

          ?

          對它前面的正則式匹配0到1次重復(fù)。ab?會匹配'a'或者'ab'。

          re.findall(r'ab?','ababbbbaabbcaacb')['ab', 'ab', 'a', 'ab', 'a', 'a']

          *?,?+?,???

          '*','+',和'?'的懶惰模式,'*','+','?'修飾符都是貪婪的,它們在字符串進(jìn)行盡可能多的匹配。有時候并不需要這種行為。在修飾符之后添加'?'將使樣式以非貪婪方式或者dfn最小方式進(jìn)行匹配,盡量少的字符將會被匹配。

          #看結(jié)果,確實(shí)有點(diǎn)太懶惰了,只匹配了a
          re.findall(r'ab*?','ababbbbaabbcaacb') ['a', 'a', 'a', 'a', 'a', 'a']

          {m}

          對其之前的正則式指定匹配m個重復(fù),少于m的話就會導(dǎo)致匹配失敗。比如,a{6}將匹配6個'a', 但是不能是5個。

          #a后面2個b
          re.findall(r'ab{2}','ababbbbaabbcaacb')['abb',?'abb']

          {m,n}

          對正則式進(jìn)行m到n次匹配,在m和n之間取盡量多,比如a{3,5}將匹配3到5個'a'。忽略m意為指定下界為0,忽略n指定上界為無限次。比如a{4,}b將匹配'aaaab'或者10000000個'a'尾隨一個'b',但不能匹配'aaab'。逗號不能省略,否則無法辨別修飾符應(yīng)該忽略哪個邊界。

          re.findall(r'ab{2,4}','ababbbbaabbcaacb')['abbbb',?'abb']
          re.findall(r'a{2}b{2,4}','ababbbbaabbcaacb')['aabb']{m,}匹配前一個字符(或者子表達(dá)式至少m次)re.findall(r'ab{2,}','ababbbbaabbcaacb')['abbbb',?'abb']

          {m,n}?

          上一個修飾符的非貪婪模式,只匹配盡量少的字符次數(shù)。比如對于'aaaaaa',a{3,5}匹配5個'a',而a{3,5}?只匹配3個'a'。

          re.findall(r'ab{2,4}?','ababbbbaabbcaacb')['abb', 'abb']
          re.findall(r'a{3,5}','aaaaaa')['aaaaa']
          re.findall(r'a{3,5}?','aaaaaa')['aaa', 'aaa'


          3、位置元字符

          ^

          匹配字符串的開頭是否包含正則表達(dá)式, 并且在MULTILINE模式也匹配換行后的首個符號。

          #匹配字符串開頭是否包含emrTre.findall(r'^[emrT]','He?was?carefully')[]#匹配開頭是否包含emrHre.findall(r'^[emrH]','He?was?carefully')?['H']#匹配開頭是否包含2個以上的are.findall(r'^a{2,}','aaabc'

          $

          匹配字符串尾或者在字符串尾的換行符的前一個字符,在MULTILINE模式下也會匹配換行符之前的文本。foo匹配 'foo' 和 'foobar',但正則表達(dá)式foo$只匹配 'foo'。在'foo1\nfoo2\n'中搜索 foo.$,通常匹配 'foo2',但在MULTILINE模式下可以匹配到 'foo1';在?'foo\n'中搜索$會找到兩個(空的)匹配:一個在換行符之前,一個在字符串的末尾。

          re.findall(r'foo','foo')['foo']
          re.findall(r'foo','foobar')['foo']
          re.findall(r'foo$','foo')['foo']
          re.findall(r'foo$','foobar') []
          re.findall(r'[ey]','He?was?carefully')['e', 'e', 'y']
          re.findall(r'[ey]$','He?was?carefully')['y']

          \A

          只匹配字符串開始。

          \Z

          只匹配字符串尾。


          \b

          匹配空字符串,但只在單詞開始或結(jié)尾的位置。一個單詞被定義為一個單詞字符的序列。注意,通常\b定義為\w和\W字符之間,或者\(yùn)w和字符串開始/結(jié)尾的邊界,意思就是r'\bfoo\b'匹配'foo','foo.','(foo)','bar foo baz'但不匹配'foobar'或者'foo3'。

          默認(rèn)情況下,Unicode字母和數(shù)字是在Unicode樣式中使用的,但是可以用ASCII標(biāo)記來更改。如果 LOCALE 標(biāo)記被設(shè)置的話,詞的邊界是由當(dāng)前語言區(qū)域設(shè)置決定的,\b 表示退格字符,以便與Python字符串文本兼容。

          \B

          匹配空字符串,但不能在詞的開頭或者結(jié)尾。意思就是r'py\B'匹配'python','py3','py2', 但不匹配'py','py.', 或者'py!'.\B是\b的取非,所以Unicode樣式的詞語是由Unicode字母,數(shù)字或下劃線構(gòu)成的,雖然可以用ASCII標(biāo)志來改變。如果使用了LOCALE標(biāo)志,則詞的邊界由當(dāng)前語言區(qū)域設(shè)置。


          4、特殊元字符

          \d

          對于Unicode (str) 樣式:匹配任何Unicode十進(jìn)制數(shù)(就是在Unicode字符目錄[Nd]里的字符)。這包括了[0-9],和很多其他的數(shù)字字符。如果設(shè)置了ASCII標(biāo)志,就只匹配[0-9]?。

          對于8位(bytes)樣式:匹配任何十進(jìn)制數(shù),就是[0-9]。

          re.findall(r'\d','chi13putao14butu520putaopi666')['1',?'3',?'1',?'4',?'5',?'2',?'0',?'6',?'6',?'6']
          re.findall(r'\d+','chi13putao14butu520putaopi666')['13',?'14',?'520',?'666']

          \D

          匹配任何非十進(jìn)制數(shù)字的字符。就是\d取非。如果設(shè)置了ASCII標(biāo)志,就相當(dāng)于[^0-9]?。

          re.findall(r'\D','chi13putao14butu520putaopi666')['c',?'h',?'i',?'p',?'u',?'t',?'a',?'o',?'b',?'u',?'t',?'u',?'p',?'u',?'t',?'a',?'o',?'p',?'i']
          re.findall(r'\D+','chi13putao14butu520putaopi666')['chi',?'putao',?'butu',?'putaopi']

          \s

          對于 Unicode (str) 樣式:匹配任何Unicode空白字符(包括[?\t\n\r\f\v]?,還有很多其他字符,比如不同語言排版規(guī)則約定的不換行空格)。如果ASCII被設(shè)置,就只匹配?[?\t\n\r\f\v]?。

          對于8位(bytes)樣式:匹配ASCII中的空白字符,就是[?\t\n\r\f\v]?。

          \S

          匹配任何非空白字符。就是\s取非。如果設(shè)置了ASCII標(biāo)志,就相當(dāng)于[^?\t\n\r\f\v]?。

          re.findall(r'\S+','chi??putao14butu?putaopi666')['chi',?'putao14butu',?'putaopi666']

          \w

          對于Unicode (str) 樣式:匹配Unicode詞語的字符,包含了可以構(gòu)成詞語的絕大部分字符,也包括數(shù)字和下劃線。如果設(shè)置了ASCII標(biāo)志,就只匹配[a-zA-Z0-9_]?。

          對于8位(bytes)樣式:匹配ASCII字符中的數(shù)字和字母和下劃線,就是[a-zA-Z0-9_]。如果設(shè)置了LOCALE標(biāo)記,就匹配當(dāng)前語言區(qū)域的數(shù)字和字母和下劃線。

          #未設(shè)置,全部匹配
          re.findall(r'\w+','chi小伍哥putao14butu真putaopi帥666')['chi小伍哥putao14butu真putaopi帥666']
          #設(shè)置了re.ASCII,只匹配數(shù)字和字母re.findall(r'\w+','chi小伍哥putao14butu真putaopi帥666',?re.ASCII)['chi',?'putao14butu',?'putaopi',?'666']

          \W

          匹配任何不是單詞字符的字符。這與\w正相反。如果使用了ASCII旗標(biāo),這就等價于[^a-zA-Z0-9_]。如果使用了LOCALE旗標(biāo),則會匹配在當(dāng)前區(qū)域設(shè)置中不是字母數(shù)字又不是下劃線的字符。

          re.findall(r'\W+','chi小伍哥putao14butu真putaopi帥666',?re.ASCII)['小伍哥',?'真',?'帥']

          [\b]

          它只在字符集合內(nèi)表示退格,比如[\b]

          ?


          5、前后查找

          import?refrom?urllib?import?request#爬蟲爬取百度首頁內(nèi)容data=request.urlopen("http://www.baidu.com/").read().decode()

          #分析網(wǎng)頁,確定正則表達(dá)式pat=r'(.*?)'result=re.search(pat,data)print(result) 1358,?1382),?match='百度一下,你就知道'>result.group() # 百度一下,你就知道'百度一下,你就知道'

          在爬取的HTML頁面中,要匹配出一對標(biāo)簽之間的文本,'</span><span style="">welcome to my page</span><span style="">',之間的文本,方法如下:

          #正則表達(dá)式re.findall(r'<[Tt][Ii][Tt][Ll][Ee]>.*?','welcome?to?my?page')#結(jié)果['welcome?to?my?page']

          分析:<[Tt][Ii][Tt][Ll][Ee]>表示不區(qū)分大小寫,這個模式匹配到了title標(biāo)簽以及它們之間的文本,但是并不完美,因?yàn)槲覀冎幌胍猼itle標(biāo)簽之間的文本,而不包括標(biāo)簽本身。為了解決類似的問題,我們就需要用到前后查找的方法。

          1)向前查找

          向前查找指定了一個必須匹配但不在結(jié)果中返回的模式。向前查找實(shí)際上就是一個子表達(dá)式,它以?=開頭,需要匹配的文本跟在=的后面。


          #使用向前查找re.findall(r'<[Tt][Ii][Tt][Ll][Ee]>.*?(?=)','welcome to my page')#返回結(jié)果['welcome to my page'</span>]</span></code><code><span id="go7utgvlrp"    class="code-snippet_outer"><span id="go7utgvlrp"    class="code-snippet__comment">#可以看大,后面?zhèn)€已經(jīng)沒有了,但是前面?zhèn)€還在,那要用到我們的向后查找#看一個提取http的例子re.findall(r'.+(?=:)','http://blog.csdn.net/mhmyqn')['http']'''分析:URL地址中協(xié)議部分是在:之前的部分,模式.+匹配任意文本,子表達(dá)式(?=:)匹配:,但是被匹配到的:并沒有出現(xiàn)在結(jié)果中。我們使用?=向正則表達(dá)式引擎表明,只要找到:就行了,但不包括在最終的返回結(jié)果里。這里如果不使用向前匹配(?=:),而是直接使用(:),那么匹配結(jié)果就會是http:了,它包括了:,并不是我們想要的。'''

          2)向后查找

          向后查找操作符是?<=。并不是所有的語言都支持向后查找,JavaScript就不支持,java語言支持向后查找。

          比如要查找文本當(dāng)中的價格(以$開頭,后面跟數(shù)字),結(jié)果不包含貨幣符號:

          文本:category1:$136.25,category2:$28,category3:$88.60

          正則表達(dá)式:(?<=\$)\d+(\.\d+)?

          結(jié)果:category1:$【136.25】,category2:$【28】,category3:$【88.60】

          分析:(?<=\$)模式匹配$,\d+(\.\d+)?模式匹配整數(shù)或小數(shù)。從結(jié)果可以看出,結(jié)果不沒有包括貨幣符號,只匹配出了價格。如果不使用向后查找,情況會是什么樣呢?使用模式$\d+(\.\d+)?,這樣會把$包含在結(jié)果中。使用模式\d+(\.\d+)?,又會把categery1(23)中的數(shù)字也匹配出來,都不是我們想要的。

          注意:向前查找模式的長度是可變的,它們可以包含.、*、+之類的元字符;而向后查找模式只能是固定長度,不能包含.、*、+之類的元字符。

          3)前后查找

          把向前查找和向后查找結(jié)合起來使用,即可解決前面HTML標(biāo)簽之間的文本的問題:


          #正則表達(dá)re.findall(r'(?<=<[Tt][Ii][Tt][Ll][Ee]>).*?(?=)','welcome to my page')#結(jié)果['welcome to my page']

          分析:從結(jié)果可以看出,問題完美的解決了。(?<=<[Tt][Ii][Tt][Ll][Ee]>)是一個向后操作,它匹配但不消費(fèi)它,(?=</[Tt][Ii][Tt][Ll][Ee]>)是一個向前操作,它匹配但不消費(fèi)它。最終返回的匹配結(jié)果只包含了標(biāo)簽之間的文本了。

          4)前后查找取非

          前面說到的向前查找和向后查找通常都是用來匹配文本,其目的是為了確定將被返回的匹配結(jié)果的文本的位置(通過指定匹配結(jié)果的前后必須是哪些文本)。這種用法叫正向前查找和正向后查找。還有一種負(fù)向前查找和負(fù)向后查找,是查找那些不與給定模式相匹配的文本。

          比如一段文本中即有價格(以$開頭,后面跟數(shù)字)和數(shù)量,我們要找出價格和數(shù)量,先來看查找價格:

          文本:I paid $30 for 10 apples, 15 oranges, and 10 pears. I saved $5 onthis order.

          正則表達(dá)式:(?<=\$)\d+

          結(jié)果:I paid 【$30】 for 10 apples, 15 oranges, and 10 pears. I saved 【$5】 on thisorder.

          re.findall(r'(?<=\$)\d+','I paid $30 for 10 apples, 15 oranges, and 10 pears. I saved $5 onthis order.')

          ['30', '5']

          查找數(shù)量:

          文本:I paid $30 for 10 apples, 15 oranges, and 10 pears. I saved $5 onthis order.

          正則表達(dá)式:\b(?

          結(jié)果:I paid $30 for 【10】 apples, 【15】 oranges, and 【10】pears. I saved $5 on this order.

          分析:(?

          5)小結(jié)

          前后查找的操作符:

          (?=)

          正向前查找

          (?!)

          負(fù)向前查找

          (?<=)

          正向后查找

          (?

          負(fù)向后查找

          有了前后查找,就可以對最終的匹配結(jié)果包含哪些內(nèi)容做出精確的控制。前后查找操作使我們可以利用子表達(dá)式來指定文本匹配操作發(fā)生的位置,并收到只匹配不消費(fèi)的效果。


          6、回溯引用

          回溯引用是正則表達(dá)式內(nèi)的一個“動態(tài)”的正則表達(dá)式,讓你根據(jù)實(shí)際的情況變化進(jìn)行匹配。說白了,就是一個根據(jù)你的需要,動態(tài)變化的表達(dá)式。

          舉個栗子:

          你原本要匹配

          之間的內(nèi)容,現(xiàn)在你知道HTML有多級標(biāo)題,你想把每一級的標(biāo)題內(nèi)容都提取出來。你也許會這樣寫:

          p?=?r".*?"

          這樣一來,你就可以將HTML頁面內(nèi)所有的標(biāo)題內(nèi)容全部匹配出來。即

          的內(nèi)容都可以被提取出來。但是我們之前說過,寫正則表達(dá)式困難的不是匹配到想要的內(nèi)容,而是盡可能的不匹配到不想要的內(nèi)容。在這個例子中,很有可能你就會被下面這樣的用例玩壞。

          比方說

          <h1>hello?worldh3>

          發(fā)現(xiàn)后面的了嗎?我們不管是怎么寫出來這樣的標(biāo)題的,但實(shí)實(shí)在在的是我們的正則表達(dá)式同樣會把這里面的hello world匹配出來。這時候就是回溯引用的重要作用。下面就是一個示例:

          import?rekey?=?r"

          hello?world

          "
          p1?=?r".*?"pattern1?=?re.compile(p1)m1?=?re.search(pattern1,key)
          print m1.group(0)#這里是會報(bào)錯的,因?yàn)槠ヅ洳坏剑闳绻麑⒃醋址某?/h1>
          #結(jié)尾就能看出效果

          看到\1了嗎?原本那個位置應(yīng)該是[1-6],但是我們寫的是\1,我們之前說過,轉(zhuǎn)義符\干的活就是把特殊的字符轉(zhuǎn)成一般的字符,把一般的字符轉(zhuǎn)成特殊字符。普普通通的數(shù)字1被轉(zhuǎn)移成什么了呢?在這里1表示第一個子表達(dá)式,也就是說,它是動態(tài)的,是隨著前面第一個子表達(dá)式的匹配到的東西而變化的。比方說前面的子表達(dá)式內(nèi)是[1-6],在實(shí)際字符串中找到了1,那么后面的\1就是1,如果前面的子表達(dá)式在實(shí)際字符串中找到了2,那么后面的\1就是2。

          類似的,\2,\3,....就代表第二個第三個子表達(dá)式。

          所以回溯引用是正則表達(dá)式內(nèi)的一個“動態(tài)”的正則表達(dá)式,讓你根據(jù)實(shí)際的情況變化進(jìn)行匹配。


          7、大小寫轉(zhuǎn)換

          \E ? ?end,表示大小寫轉(zhuǎn)換的結(jié)束范圍

          \l ? ? ?low,表示把下一個字符轉(zhuǎn)為小寫

          \L Low,表示把\L與\E之間的字符轉(zhuǎn)為小寫

          \u up,表示把下一個字符轉(zhuǎn)為大寫

          \U Up,表示把\U與\E之間的字符轉(zhuǎn)為大寫



          五、常量模塊

          下面我們來快速學(xué)習(xí)這些常量的作用及如何使用他們,按常用度排序!

          1、IGNORECASE

          語法: re.IGNORECASE 或簡寫為 re.I

          含義: 進(jìn)行忽略大小寫匹配。

          re.findall(r'TM','小伍哥tm真帥')[]re.findall(r'TM','小伍哥tm真帥',re.IGNORECASE)['tm']

          在默認(rèn)匹配模式下小寫字母tm無法匹配大寫字母TM的,而在忽略大小寫模式下就可以匹配了。


          2、ASCII

          語法: re.ASCII 或簡寫為 re.A

          作用: 顧名思義,ASCII表示ASCII碼的意思,讓 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode。

          re.findall(r'\w+','小伍哥tm真帥')['小伍哥tm真帥']#w匹配所有字符
          re.findall(r'\w+','小伍哥tm真帥',re.ASCII)#w匹配字母和數(shù)字['tm']

          在默認(rèn)匹配模式下'\w+'匹配到了所有字符串,而在ASCII模式下,只匹配到了a、b、c(也就是指匹配ASCII編碼支持的字符)。注意:這只對字符串匹配模式有效,對字節(jié)匹配模式無效。


          3、DOTALL

          語法: re.DOTALL 或簡寫為 re.S

          作用: DOT表示.,ALL表示所有,連起來就是.匹配所有,包括換行符\n。默認(rèn)模式下.是不能匹配行符\n的。

          print('小伍哥\n真帥')#文本中間包含換行符,打印的時候會換行小伍哥真帥re.findall(r'.*','小伍哥\n真帥')['小伍哥', '', '真帥', '']re.findall(r'.*','小伍哥\n真帥',re.DOTALL?)['小伍哥\n真帥', '']

          在默認(rèn)匹配模式下.并沒有匹配換行符\n,而是將字符串分開匹配;而在re.DOTALL模式下,換行符\n與字符串一起被匹配到。


          4、MULTILINE

          語法: re.MULTILINE 或簡寫為 re.M

          含義: 多行模式,當(dāng)某字符串中有換行符\n,默認(rèn)模式下是不支持換行符特性的,比如:行開頭和行結(jié)尾,而多行模式下是支持匹配行開頭的。

          print('小伍哥\n真帥')#文本中間包含換行符,打印的時候會換行小伍哥真帥re.findall(r'^真帥','小伍哥\n真帥')[]
          re.findall(r'^真帥','小伍哥\n真帥',re.MULTILINE)['真帥']

          正則表達(dá)式中^表示匹配行的開頭,默認(rèn)模式下它只能匹配字符串的開頭;而在多行模式下,它還可以匹配 換行符\n后面的字符。

          注意:正則語法中^匹配行開頭、\A匹配字符串開頭,單行模式下它兩效果一致,多行模式下\A不能識別\n。


          5、VERBOSE

          語法: re.VERBOSE 或簡寫為 re.X

          作用: 詳細(xì)模式,可以在正則表達(dá)式中加注解!

          text??=?'小伍哥tm帥'
          pat???=?'''小伍哥?#?人名,本文作者 tm # 強(qiáng)調(diào)程度 帥 # 形容詞 '''re.findall(pat,text)[]re.findall(pat,text,re.VERBOSE)['小伍哥tm帥']

          可以看到,默認(rèn)模式下無法識別正則表達(dá)式中的注釋,而詳細(xì)模式是可以識別的。當(dāng)一個正則表達(dá)式十分復(fù)雜的時候,詳細(xì)模式或許能為你提供另一種注釋方式,但它不應(yīng)該成為炫技的手段,建議謹(jǐn)慎使用!


          6、LOCALE

          語法: re.LOCALE 或簡寫為 re.L

          作用: 由當(dāng)前語言區(qū)域決定 \w, \W, \b, \B 和大小寫敏感匹配,這個標(biāo)記只能對byte樣式有效,該標(biāo)記官方已經(jīng)不推薦使用,因?yàn)檎Z言區(qū)域機(jī)制很不可靠,它一次只能處理一個 "習(xí)慣”,而且只對8位字節(jié)有效。


          7、UNICODE

          語法: re.UNICODE 或簡寫為 re.U

          作用: 與 ASCII常量類似,匹配unicode編碼支持的字符,但是Python3默認(rèn)字符串已經(jīng)是Unicode,所以顯得有點(diǎn)多余。


          8、DEBUG

          語法: re.DEBUG

          作用: 顯示編譯時的debug信息。

          re.findall(r'tm','小伍哥tm真帥',re.DEBUG)
          LITERAL 116LITERAL 109
          0. INFO 10 0b11 2 2 (to 11) prefix_skip 2 prefix [0x74, 0x6d] ('tm') overlap [0, 0]11: LITERAL 0x74 ('t')13. LITERAL 0x6d ('m')15. SUCCESSOut[97]: ['tm']

          ?

          9、TEMPLATE

          語法: re.TEMPLATE 或簡寫為 re.T

          作用: disable backtracking(禁用回溯),也就是在正則匹配的過程中,匹配錯誤后不進(jìn)行回溯處理。

          re.findall(r'ab{1,3}c','abbc')['abbc']re.findall(r'ab{1,3}c','abbc',re.TEMPLATE)error:?internal:?unsupported?template?operator?MAX_REPEAT

          我們看看正則一步一步分解匹配過程:

          • 正則引擎先匹配 a。

          • 正則引擎盡可能多地(貪婪)匹配 b{1,3}中的 b。

          • 正則引擎去匹配 b,發(fā)現(xiàn)沒 b 了,糟糕!趕緊回溯!所以第一個案例沒禁止,能匹配,第二個案例有禁止,系統(tǒng)報(bào)錯

          • 返回 b{1,3}這一步,不能這么貪婪,少匹配個 b。

          • 正則引擎去匹配 b。

          • 正則引擎去匹配 c,完成匹配。

          以上,就是一個簡單的回溯過程,不進(jìn)行回溯有可能匹配不到滿足條件的匹配項(xiàng)

          ?

          10、常量總結(jié)

          1)9個常量中,前5個(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用處,兩個(LOCALE、UNICODE)官方不建議使用、兩個(TEMPLATE、DEBUG)試驗(yàn)性功能,不能依賴。

          2)常量在re常用函數(shù)中都可以使用,查看源碼可得知。

          3)常量可疊加使用,因?yàn)槌A恐刀际?的冪次方,所以是可以疊加使用的,疊加時請使用 | 符號而不是+ 符號!

          re.findall(r'TM','小伍哥\ntm真帥')[]re.findall(r'TM','小伍哥\ntm真帥',re.IGNORECASE|re.MULTILINE)['tm']


          六、函數(shù)模塊

          正則表達(dá)re模塊共有12個函數(shù),我將分類進(jìn)行講解,這樣方便記憶與理解,先來看看概覽:

          • search、match、fullmatch:查找一個匹配項(xiàng)

          • findall、finditer:查找多個匹配項(xiàng)

          • split: 分割

          • sub,subn:替換

          • compile函數(shù)template函數(shù): 將正則表達(dá)式的樣式編譯為一個 正則表達(dá)式對象

          print(dir(re))[......?'compile',?'copyreg',?'enum',?'error',?'escape',?'findall',?'finditer',?'fullmatch',?'functools',?'match',?'purge',?'search',?'split',?'sre_compile',?'sre_parse',?'sub',?'subn',?'template']

          1、查找一個匹配項(xiàng)

          查找并返回一個匹配項(xiàng)的函數(shù)有3個:search、match、fullmatch,他們的作用分別是:

          search:查找任意位置的匹配項(xiàng)

          match:必須從字符串開頭匹配

          fullmatch:整個字符串與正則完全匹配

          1) search()

          描述:在給定字符串中尋找第一個匹配正則表達(dá)式的子字符串,如果找到會返回一個Match對象,這個對象中的元素可以group()得到(之后將會介紹group的概念),如果沒找到就會返回None。調(diào)用re.match,re.search方法或者對re.finditer結(jié)果進(jìn)行遍歷,輸出的結(jié)果都是re.Match對象

          語法:re.search(pattern, string, flags=0)

          • pattern 匹配的正則表達(dá)式

          • string 要匹配的字符串

          • flags 標(biāo)志位,用于控制正則表達(dá)式的匹配方式

          re.search(r"(\w)(.\d)","as.21").group()'s.2'

          假設(shè)返回的Match對象為m,m.group()來取某組的信息,group(1)返回與第一個子模式匹配的單個字符串,group(2)等等以此類推,start()方法得到對應(yīng)組的開始索引,end()得到對應(yīng)組的結(jié)束索引,span()以元組形式給出對應(yīng)組的開始和結(jié)束位置,括號中填入組號,不填入組號時默認(rèn)為0。

          匹配對象m方法有很多,幾個常用的方法如下:

          m.start()?返回匹配到的字符串的起使字符在原始字符串的索引

          m.end()?返回匹配到的字符串的結(jié)尾字符在原始字符串的索引

          m.group()?返回指定組的匹配結(jié)果

          m.groups()?返回所有組的匹配結(jié)果

          m.span() 以元組形式給出對應(yīng)組的開始和結(jié)束位置

          其中的組,是指用()括號括起來的匹配到的對象,比如下列中的"(\w)(.\d)",就是兩個組,第一個組匹配字母,第二個組匹配.+一個數(shù)字。

          m?=?re.search(r"(\w)(.\d)","as.21")m1,?4),?match='s.2'>
          m.group()?s.2m.group(0)'s.2'm.group(1)?#根據(jù)要求返回特定子組's'm.group(2)'.2'm.start()1m.start(2)#第二個組匹配的索引位置2m.groups()('s',?'.21')m.span()(1, 5)

          2) match()

          描述:必須從字符串開頭匹配,同樣返回的是Match對象,對應(yīng)的方法與search方法一致,此處不再贅述。

          語法:re.match(pattern, string, flags=0)

          • pattern ? 匹配的正則表達(dá)式

          • string ?要匹配的字符串

          • flags ? 標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫,多行匹配等等

          #從頭開始匹配,返回一個數(shù)字,發(fā)現(xiàn)報(bào)錯,無法返回,因?yàn)椴皇菙?shù)字開頭的
          text?=?'chi13putao14butu520putaopi666'pattern?=?r'\d+'re.match(pattern,text).group()AttributeError:?'NoneType'?object?has?no?attribute?'group'
          #從頭開始匹配,返回一個單詞,正常返回了開頭的單詞text?=?'chi13putao14butu520putaopi666'pattern?=?r'[a-z]+'re.match(pattern,text).group()'chi'

          3) fullmatch()

          描述:整個字符串與正則完全匹配,同樣返回的是Match對象,對應(yīng)的方法與search方法一致,此處不再贅述

          語法:(pattern, string, flags=0)

          • pattern ? 匹配的正則表達(dá)式

          • string ?要匹配的字符串

          • flags ? 標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫,多行匹配等等

          #必須要全部符合條件才能匹配re.fullmatch(r'[a-z]+','chiputao14').group()AttributeError:?'NoneType'?object?has?no?attribute?'group'
          re.fullmatch(r'[a-z]+','chiputao').group()'chiputao'

          2、查找多個匹配項(xiàng)

          講完查找一項(xiàng),現(xiàn)在來看看查找多項(xiàng)吧,查找多項(xiàng)函數(shù)主要有:findall函數(shù)finditer函數(shù)

          1)findall: 從字符串任意位置查找,返回一個列表

          2)finditer:從字符串任意位置查找,返回一個迭代器

          兩個函數(shù)功能基本類似,只不過一個是返回列表,一個是返回迭代器。我們知道列表是一次性生成在內(nèi)存中,而迭代器是需要使用時一點(diǎn)一點(diǎn)生成出來的,運(yùn)行時占用內(nèi)存更小。如果存在大量的匹配項(xiàng)的話,建議使用finditer函數(shù),一般情況使兩個函數(shù)不會有太大的區(qū)別。

          1)findall

          描述:返回字符串里所有不重疊的模式串匹配,以字符串列表的形式出現(xiàn)。

          語法:re.findall(pattern, string, flags=0)

          • pattern ? 匹配的正則表達(dá)式

          • string ?要匹配的字符串

          • flags ? 標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫,多行匹配等等

          import?retext????=?'Python太強(qiáng)大,我愛學(xué)Python'pattern?=?'Python're.findall(pattern,text)['Python',?'Python']#找出下列字符串中的數(shù)字text?=?'chi13putao14butu520putaopi666'#\d+表示匹配任意數(shù)字pattern?=?r'\d+'re.findall(pattern,text)['13',?'14',?'666',?'520']?
          text?=?'ab-abc-a-cccc-d-aabbcc'pattern?=?'ab*'re.findall(pattern,text)['ab',?'ab',?'a',?'a',?'abb']
          #找到所有副詞'''findall()?匹配樣式?所有?的出現(xiàn),不僅是像 search()?中的第一個匹配。比如,如果一個作者希望找到文字中的所有副詞,他可能會按照以下方法用?findall()'''text = "He was carefully disguised but captured quickly by police."re.findall(r"\w+ly", text)['carefully',?'quickly']

          2)finditer()

          描述:返回一個產(chǎn)生匹配對象實(shí)體的迭代器,能產(chǎn)生字符串中所有RE模式串的非重疊匹配。

          語法:re.finditer(pattern, string, flags=0)

          • pattern ? 匹配的正則表達(dá)式

          • string ?要匹配的字符串

          • flags ? 標(biāo)志位,用于控制正則表達(dá)式的匹配方式,如:是否區(qū)分大小寫,多行匹配等等

          m?=?re.finditer("Python","Python非常強(qiáng)大,我愛學(xué)習(xí)Python")m?for?i?in?m:    print(i.group(0))PythonPython#找到所有副詞和位置
          '''如果需要匹配樣式的更多信息,?finditer()?可以起到作用,它提供了?匹配對象?作為返回值,而不是字符串。繼續(xù)上面的例子,如果一個作者希望找到所有副詞和它的位置,可以按照下面方法使用?finditer()'''text?=?"He?was?carefully?disguised?but?captured?quickly?by?police."for?m?in?re.finditer(r"\w+ly",?text):????print('%02d-%02d:?%s'?%?(m.start(),?m.end(),?m.group(0)))
          07-16: carefully40-47: quic

          3、匹配項(xiàng)分割

          1)split()

          描述:split能夠按照所能匹配的字串將字符串進(jìn)行切分,返回切分后的字符串列表

          形式.切割功能非常強(qiáng)大

          語法:re.split(pattern, string, maxsplit=0, flags=0)

          • pattern:匹配的字符串

          • string:需要切分的字符串

          • maxsplit:分隔次數(shù),默認(rèn)為0(即不限次數(shù))

          • flags:標(biāo)志位,用于控制正則表達(dá)式的匹配方式,flags表示模式,就是上面我們講解的常量!支持正則及多個字符切割。

          正則表達(dá)的分割函數(shù)與字符串的分割函數(shù)一樣,都是split,只是前面的模塊不一樣,正則表達(dá)的函數(shù)為, ,用pattern分開string,maxsplit表示最多進(jìn)行分割次數(shù),

          re.split(r";","var?A;B;C:integer;")['var?A',?'B',?'C:integer',?'']
          re.split(r"[;:]","var?A;B;C:integer;")['var?A',?'B',?'C',?'integer',?'']
          text?=?'chi13putao14butu520putaopi666'pattern?=?r'\d+'re.split(pattern,text)['chi',?'putao',?'butu',?'putaopi',?'']
          line?=?'aac?bba?ccd;dde???eef,fff'#單字符切割re.split(r';',line)['aac?bba?ccd',?'dde???eef,fff']
          #兩個字符以上切割需要放在?[?]?中re.split(r'[;,]',line)['aac?bba?ccd',?'dde???eef',?'fff']#所有空白字符切割re.split(r'[;,\s]',line)['aac',?'bba',?'ccd',?'dde',?'',?'',?'eef',?'fff']#使用括號捕獲分組,默認(rèn)保留分割符re.split(r'([;])',line)['aac?bba?ccd',?';',?'dde???eef,fff']
          #不想保留分隔符,以(?:...)的形式指定re.split(r'(?:[;])',line)['aac?bba?ccd',?'dde???eef,fff']#不想保留分隔符,以(?:...)的形式指定re.split(r'(?:[;,\s])',line)['aac',?'bba',?'ccd',?'dde',?'',?'',?'eef',?'fff']

          注意:str模塊也有一個split函數(shù) ,那這兩個函數(shù)該怎么選呢?str.split函數(shù)功能簡單,不支持正則分割,而re.split支持正則。關(guān)于二者的速度如何?來實(shí)際測試一下,在相同數(shù)據(jù)量的情況下使用re.split函數(shù)與str.split函數(shù)執(zhí)行次數(shù) 與 執(zhí)行時間 對比圖:

          #運(yùn)行時間統(tǒng)計(jì) 只計(jì)算了程序運(yùn)行的CPU時間,且每次測試時間有所差異import time#統(tǒng)計(jì)次數(shù)n?=?1000``start_t = time.perf_counter()for i in range(n):     re.split(r';',line)##re.splitend_t = time.perf_counter()print ('re.split: '+str(round(1000000*(end_t-start_t),2)))

          start_t?=?time.perf_counter()for i in range(n): line.split(';')##str.splitend_t = time.perf_counter()print ('str.split: '+str(round(1000000*(end_t-start_t),2)))

          通過上圖對比發(fā)現(xiàn),5000次循環(huán)以內(nèi)str.split函數(shù)和re.split函數(shù)執(zhí)行時間差異不大,而循環(huán)次數(shù)1000次以上后str.split函數(shù)明顯更快,而且次數(shù)越多差距越大!

          所以結(jié)論是,在不需要正則支持的情況下使用str.split函數(shù)更合適,反之則使用re.split函數(shù)。具體執(zhí)行時間與測試數(shù)據(jù)有關(guān)!且每次測試時間有所差異

          ?

          4、匹配項(xiàng)替換

          替換主要有sub函數(shù)與subn函數(shù)兩個函數(shù),他們功能類似,不同點(diǎn)在于sub只返回替換后的字符串,subn返回一個元組,包含替換后的字符串和替換次數(shù)。

          python 里面可以用 replace 實(shí)現(xiàn)簡單的替換字符串操作,如果要實(shí)現(xiàn)復(fù)雜一點(diǎn)的替換字符串操作,需用到正則表達(dá)式。

          re.sub用于替換字符串中匹配項(xiàng),返回一個替換后的字符串,subn方法與sub()相同, 但返回一個元組, 其中包含新字符串和替換次數(shù)。

          sub是substitute表示替換。

          1)sub

          描述:它的作用是正則替換。

          語法:re.sub(pattern, repl, string, count=0, flags=0)

          • pattern:該參數(shù)表示正則中的模式字符串;

          • repl:repl可以是字符串,也可以是可調(diào)用的函數(shù)對象;如果是字符串,則處理其中的反斜杠轉(zhuǎn)義。如果它是可調(diào)用的函數(shù)對象,則傳遞match對象,并且必須返回要使用的替換字符串

          • string:該參數(shù)表示要被處理(查找替換)的原始字符串;

          • count:可選參數(shù),表示是要替換的最大次數(shù),而且必須是非負(fù)整數(shù),該參數(shù)默認(rèn)為0,即所有的匹配都會被替換;

          • flags:可選參數(shù),表示編譯時用的匹配模式(如忽略大小寫、多行模式等),數(shù)字形式,默認(rèn)為0。

          把字符串?aaa34bvsa56s中的數(shù)字替換為?*號

          import?rere.sub('\d+','*','aaa34bvsa56s')#連續(xù)數(shù)字替換'aaa*bvsa*s're.sub('\d','*','aaa34bvsa56s')#每個數(shù)字都替換一次'aaa**bvsa**s'#只天換一次count=1,第二次的數(shù)字沒有被替換re.sub('\d+','*','aaa34bvsa56s',count=1)'aaa*bvsa56s'把chi13putao14butu520putaopi666中的數(shù)字換成...text?=?'chi13putao14butu520putaopi666'pattern?=?r'\d+'re.sub(pattern,'...',text)'chi...putao...butu...putaopi...'

          關(guān)于第二個參數(shù)的用法,我們可以看看下面的內(nèi)容

          #定義一個函數(shù)def?refun(repl):    print(type(repl))    return('...')re.sub('\d+',refun,'aaa34bvsa56s')<class 're.Match'><class 're.Match'>'aaa...bvsa...s'

          從上面的例子看來,似乎沒啥區(qū)別

          原字符串中有多少項(xiàng)被匹配到,這個函數(shù)就會被調(diào)用幾次。

          至于傳進(jìn)來的這個match對象,我們調(diào)用它的.group()方法,就能獲取到被匹配到的內(nèi)容,如下所示:

          def?refun(repl):    print(type(repl),repl.group())    return('...')re.sub('\d+',refun,'aaa34bvsa56s')<class 're.Match'> 34<class 're.Match'> 56Out[113]: 'aaa...bvsa...s'

          這個功能有什么用呢?我們設(shè)想有一個字符串moblie18123456794num123,這個字符串中有兩段數(shù)字,并且長短是不一樣的。第一個數(shù)字是11位的手機(jī)號。我想把字符串替換為:moblie[隱藏手機(jī)號]num***。不是手機(jī)號的數(shù)字,每一位數(shù)字逐位替換為星號。

          def?refun(repl):????if?len(repl.group())?==?11:        return '[隱藏手機(jī)號]'    else:        return '*' * len(repl.group())re.sub('\d+',?refun,?'moblie18217052373num123')'moblie[隱藏手機(jī)號]num***'

          ?

          2)subn

          描述:函數(shù)與 re.sub函數(shù) 功能一致,只不過返回一個元組 (字符串, 替換次數(shù))。

          語法:re.subn(pattern, repl, string, count=0, flags=0)

          參數(shù):同re.sub

          re.subn('\d+','*','aaa34bvsa56s')#連續(xù)數(shù)字替換('aaa*bvsa*s',?2)
          re.subn('\d','*','aaa34bvsa56s')#每個數(shù)字都替換一次('aaa**bvsa**s',?4)
          text?=?'chi13putao14butu520putaopi666'pattern?=?r'\d+'re.subn(pattern,'...',text)('chi...putao...butu...putaopi...',?4)

          ?

          5、編譯正則對象

          描述:將正則表達(dá)式的樣式編譯為一個正則表達(dá)式對象(正則對象),可以用于匹配

          語法:re.compile(pattern,?flags=0)

          參數(shù):

          • pattern:該參數(shù)表示正則中的模式字符串;

          • flags:可選參數(shù),表示編譯時用的匹配模式(如忽略大小寫、多行模式等),數(shù)字形式,默認(rèn)為0。

          prog???=?re.compile(pattern)result?=?prog.match(string)等價于result?=?re.match(pattern,?string)

          如果需要多次使用這個正則表達(dá)式的話,使用re.compile()和保存這個正則對象以便復(fù)用,可以讓程序更加高效。


          6、轉(zhuǎn)義函數(shù)

          re.escape(pattern) 可以轉(zhuǎn)義正則表達(dá)式中具有特殊含義的字符,比如:. 或者 * re.escape(pattern) 看似非常好用省去了我們自己加轉(zhuǎn)義,但是使用它很容易出現(xiàn)轉(zhuǎn)義錯誤的問題,所以并不建議使用它轉(zhuǎn)義,而建議大家自己手動轉(zhuǎn)義!

          7、緩存清除函數(shù)

          re.purge()函數(shù)作用就是清除正則表達(dá)式緩存,清除后釋放內(nèi)存。

          六、異常模塊

          re模塊還包含了一個正則表達(dá)式的編譯錯誤,當(dāng)我們給出的正則表達(dá)式是一個無效的表達(dá)式(就是表達(dá)式本身有問題)時,就會raise一個異常。

          ?


          往期精彩回顧





          本站知識星球“黃博的機(jī)器學(xué)習(xí)圈子”(92416895)

          本站qq群704220115。

          加入微信群請掃碼:


          瀏覽 36
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一级a一级a看免费视频 | 一级黄色毛片播放 | 无码高清视频 | 国产熟女AV | 欧美高清在线 |