天天看點

正規表達式一、正則基本知識二 、兩種使用方法三、函數四、擴充知識五、 常用一些正則

一、正則基本知識

  正則在python中是以c實作的,在後續的爬蟲等工作都需要使用到該子產品,主要搜尋文本的内容。搜尋非常速度。

  http://tool.oschina.net/regex 

  https://www.regexpal.com/      兩個個線上的正規表達式,可以用來借鑒

1.1 正則常用的比對規則

  下面是列舉出來一些常用的,更多的使用help(re)檢視。

    正則預設都是貪婪比對的(盡可能的多,貪吃)。還有一種懶惰比對(取到最少那次就不幹活了)。

    ?是一個非常有意思的規則。 自己單獨的時候,表示0或1個字元。

       和貪婪的組合在一起的時候,就變成了控制貪婪變成懶惰比對了。

.         代表任意字元,但是除了換行符
# 開頭和結尾
    ^         代表字元串的開始            
    $         代表字元串的結尾 ,如果是多行文本,預設隻比對第一行的結尾。
# 任意字元,貪婪比對
    *         比對0或多次,貪婪比對,取到滿足的最多  
    +         比對1或多次,貪婪比對,取到滿足的最多   
    ?         比對0或一次,貪婪比對,取到滿足的最多   
                  ?還可結合*,+,?做懶惰比對
# ?組合-懶惰比對
    *?   +?   ??  前面的任意字元,得到最少的那次

# 指定次數 比對
    {m}      比對m次。
    {m,n}    比對m到n次,和切片的使用方法一緻。也是貪婪比對
                    {m,}   m到無窮
                    {n,}    0 到n次
                    a{m}   比對6個a
    {m,n}?   更改成懶惰,得到最少的那次比對
# 分組
    ()       下面會詳細的講解
# 字元集
  [] 隻取其中一個 
        [0-9]     代表 1到9,
        [a-z]     代表 a到z      
        [a-zA-z0-9]  所有的字元和數字
        [abc]     比對任意一個
        [^9]     除了9以外其他的所有
# 或
  |      常常搭配字元集和分組使用,[a|b]:找到a了,就不找b了,反之相同。
      

1.2 轉義字元 \

   python的正則規則是以引号 包圍的,裡面的的一些字元 要代表本身的含義,或 轉成其他意思,就需要這個\。

   紅色的為常用的。

\.        預設.是代表任意字元,我們可以讓他轉義為。本身
\A       隻在字元串開頭進行比對。
\b       比對位于開頭或者結尾的空字元串
\B       比對不位于開頭或者結尾的空字元串
\d       比對任意十進制數,相當于 [0-9]
\D       比對任意非數字字元,相當于 [^0-9]
\s       比對任意空白字元,相當于 [ \t\n\r\f\v]
\S       比對任意非空白字元,相當于 [^ \t\n\r\f\v]
\w       比對任意數字和字母,相當于 [a-zA-Z0-9_]
\W       比對任意非數字和字母的字元,相當于 [^a-zA-Z0-9_]
\Z       隻在字元串結尾進行比對
\number  在分組中使用,類似占位符      

二 、兩種使用方法

2.1 方法1:compile

  利用compile方法,生成一個re對象,好處是可以多次使用

import re
res = re.compile('\d{3}')            # 第一步,把正則字元串進行編碼,傳回一個re對象,儲存為一個常量
result = res.search('I am hui 123')  # 第二步,把compile傳回的對象,去比對字元串,傳回一個mactch對象
result.group()                       # 第三步,使用match對象的group方法,傳回實際比對的對象      

    正則支援鍊式程式設計

2.2 方法2:re.方法

  直接使用re的方法,對于單一的使用比較友善,如果每次使用,每次都要定義。

import re
x = re.search('\d{3}', 'I am hui 123') # 直接使用match對象
x.group()                              # 使用match對象的group方法,傳回實際比對的對象      

    正則支援鍊式程式設計

三、函數

3.1 compile

   compile(pattern, flags=0)

    Compile a regular expression pattern into a regular expression object re.compile(pattern, flags=0)

    把正規表達式的模式和辨別轉化成正規表達式對象,供 match() 和 search() 這兩個 函數使用。

  常用的flags: 

re.I    忽略大小寫
re.L    表示特殊字元集 \w, \W, \b, \B, \s, \S 依賴于目前環境
re.M    多行模式
re.S    把‘.’切換成 包含換行符,預設 點 是不包含換行符号的。
re.X    為了增加可讀性,忽略空格和’ # ’後面的注釋      

  一個正則的注釋的列子:

import re

regex = re.compile(r'(\d{1,3}\.){3}\d{1,3}')  # 錯誤寫法
regex = re.compile(r'''
(2[0-4]\d|25[0-5]|[01]?\d\d?\.)  # 代表一組ip,包含後面的點
{3}                              # 表示3組
(2[0-4]\d|25[0-5]|[01]?\d\d?)    # 最後一組數字
''', re.X)
print(regex.match('192.168.1.1'))
print(regex.match('999.999.999.999'))  # 非正常的ip      

3.2 seach 

  搜尋整個字元串,傳回第一個比對的對象-match對象

  search(pattern, string, flags=0)

    Scan through string looking for a match to the pattern, returning

    a match object, or None if no match was found.

import re
s = """
1334-1234-113
133-1234-2123
135-4567-3456
[email protected]
[email protected]
[email protected]
https://github.com
https://taobcom.com
"""
target = '\d{4}'
target = '\d{3}(-\d{4}){2}'
regex = re.compile(target)
result = re.search(regex, s)
if result:
    print(result.group())
else:
    print('找不到')      

3.2 match

  比對字元串的開頭,符合則傳回一個match對象。

  注意match 和 seach的不同。兩者都是隻比對一次,找到符合就傳回,後面的就不再比對。如果不符合就傳回None

      macth:隻比對字元串的開頭,注意前面的空白字元,特别是/n 換行。

      seach:搜尋整個字元串。

import re
reg = re.compile('\d{3}')
s1 = '1234dasd'            # 正常内容
s2 = '/n1234dasd'         # 前面有換行符
s3 = ' 123'                    # 前面有空格
print(reg.match(s1))
print(reg.match(s2))
print(reg.match(s3))      

結果:
<_sre.SRE_Match object; span=(0, 3), match='123'>
None
None      

3.3 findall

  比對所有的字元串,到結束為之。傳回一個清單。

import re
s = 'ferfewf234ed3de8ge4r3434rde8ger3r3rde8gede8ger34rf34r'

rege = re.compile('de8ge')
# rege = re.compile('de(8)ge')  # 進行分組
result = rege.findall(s)
print(result)      

3.4 spilit

  使用正則的規則,來進行分割。類似字元串的spilt

import re

s = 'ferfewf234ed3de8ge4r3434rde8ger3r3rde8gede8ger34rf34r'
rege = re.compile('de8ge')    # 抛棄了de8ge
rege = re.compile('(de8ge)')  # 以de8ge進行分割,但是會傳回de8ge
result = rege.split(s)
print(result)      

3.5 sub 

  字元串中也有字元串的替換,replace,。正則中使用sub來替換字元串的内容,比起字元串的内容,整體更靈活。

第一種使用分組進行替換

import re
s = '字元串格式: 10/01/2008,  12/25/2018'
re_date = re.compile(r'(\d+)/(\d+)/(\d+)') # r是raw的意思,原生字元串
x=re_date.sub(r'\3-\1-\2', s)
print(x)      

第二種 進行字元替換

import re
s = """
pytyhon is hard to learn,   堅持下,
沒多少了        ok?
"""
# print(s)
regex = re.compile('\s+')
print(regex.sub('', s))      

四、擴充知識

4.1 貪婪比對 與 懶惰比對

    ?是一個非常有意思的規則。

        1.  自己單獨的時候,表示0或1個字元。

        2. 和貪婪的組合在一起的時候,就變成了控制貪婪變成懶惰比對了。

*?             重複任意次,但盡可能少重複
+?             重複1次或更多次,但盡可能少重複
??             重複0次或1次,但盡可能少重複
{n,m}?         重複n到m次,但盡可能少重複
{n,}?          重複n次以上,但盡可能少重複      
# 小案列,想比對引号内部的,說話的内容
import re
text = 'Ipone say "yes." PC say "No."'
regex = re.compile('"(.*)"')    # 使用貪婪比對,會得到最長的那串
#regex = re.compile('"(.*?)"') # 加上?,變成懶惰比對就正常了   
print(regex.findall(text))      

4.2 分組

  分組是用()來表示的,分組在我個人感覺 有三種作用:

    1.   将某些規律看成是一組,然後進行組級别的重複。

    2.   分組之後,可以通過後向引用簡化表達式。

    3.   和find組合,查找指定的字元

第一個作用

  用ip位址(這個是簡單版本,ip的真實看上面)作為執行個體:

\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
但仔細觀察,我們可以發現一定的規律,可以把.\d{1,3}看成一個整體,也就是把他們看成一組,再把這個組重複3次即可。表達式如下:
    \d{1,3}(\.\d{1,3}){3}
這樣一看,就比較簡潔了。      

第二個作用:

  首先強調一個知識點,後向引用,指派的是比對後的結果,非正規表達式。

<title>.*</title>

       可以看出,上邊表達式中有兩個title,完全一樣,其實可以通過分組簡寫。表達式如下:

       <(title)>.*</\1>

       這個例子實際上就是反向引用的實際應用。對于分組而言,整個表達式永遠算作第0組,在本例中,第0組是<(title)>.*</\1>,然後從左到右,依次為分組編号,是以,(title)是第1組。

       用\1這種文法,可以引用某組的文本内容,\1當然就是引用第1組的文本内容了,這樣一來,就可以簡化正規表達式,隻寫一次title,把它放在組裡,然後在後邊引用即可。

       以此為啟發,我們可不可以簡化剛剛的IP位址正規表達式呢?原來的表達式為\d{1,3}(.\d{1,3}){3},裡邊的\d{1,3}重複了兩次,如果利用後向引用簡化,表達式如下:

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

       簡單的解釋下,把\d{1,3}放在一組裡,表示為(\d{1,3}),它是第1組,(.\1)是第2組,在第2組裡通過\1文法,後向引用了第1組的文本内容。

       經過實際測試,會發現這樣寫是錯誤的,為什麼呢?

       小菜一直在強調,後向引用,引用的僅僅是文本内容,而不是正規表達式!

       也就是說,組中的内容一旦比對成功,後向引用,引用的就是比對成功後的内容,引用的是結果,而不是表達式。

       是以,(\d{1,3})(.\1){3}這個表達式實際上比對的是四個數都相同的IP位址,比如:123.123.123.123。      

第三作用:

  和find組合,提取組的内容。 先比對整個正規表達式,根據結果再次提取()裡面的内容

import re
data = '''
○ 4.1日,共有4人面試,手機号分别是13812345678,15112345678,13812345678,15112345678
○ 4.5日,共有6人面試13812345678,15112345678,13812345678,15112345678,13812345678,15112345678
○ 4.7日,共有3人面試13812345678,15112345678,13812345678
○ 4.8日,共有5人面試15112345678,13812345678,15112345678,13812345678,15112345678
4.30日,共有6人面試13812345678,15112345678,13812345678,15112345678,13812345678,15112345678
'''

regex = re.compile('共有(\d+)人')  # 先比對整個正規表達式,根據結果再次提取()裡面的内容
sum_people = sum([int(i) for i in regex.findall(data)])
print(sum_people)      

分組命名:

  對于後向引用采用編号的方式進行替換,容易混淆,采用命名的方式便于識别

import re
# regex = re.compile(r'(\d+)\.(\d+)')                 # 使用編号替換,但是容易混淆,下面的方式采用命名
# print(regex.sub(r'\1月\2日', memo_text))

regex = re.compile(r'(?P<month>\d+)\.(?P<day>\d+)')
print(regex.sub(r'\g<month>月\g<day>日', memo_text))      

    

五、 常用一些正則

import re

RE_PHONE = re.compile('\d{3}-\d{8}|\d{4}-\d{7}')


def phone(str1: str)-> list:
    "輸入一個字元串,從中傳回一個清單"
    return RE_PHONE.findall(str1)


def main():
    s = """
    010-23293293deuju010-23223293
    0111-3234123
    """
    print(phone(s))

if __name__ == '__main__':
    main()      

比對電話号碼

比對騰訊QQ号:  [1-9][0-9]{4,}  騰訊QQ号從10000開始 
隻能輸入漢字:  ^[\u4e00-\u9fa5]{1,8}$ 
隻能輸入由數字和26個英文字母組成的字元串:  “^[A-Za-z0-9]+$” 
驗證使用者密碼:  “^[a-zA-Z]\w{7,17}$”正确格式為:以字母開頭, 長度在8-18之間, 隻能包含字元、數字和下劃線。      
import re

# 驗證電話
RE_PHONE = re.compile('\d{3}-\d{8}|\d{4}-\d{7}')
# 驗證漢字
RE_CH = re.compile('^[\u4e00-\u9fa5]{1,8}$')
# 驗證密碼
RE_PWD = re.compile('^[a-zA-Z]\w{7,17}$')


def phone(text: str)-> list:
    "輸入一個字元串,從中傳回一個清單"
    return RE_PHONE.findall(text)


def verify(regex: '正規表達式', text: str)-> list:
    "驗證使用者名和密碼"
    if regex.match(text):
        return True
    else:
        return False


def main():
    s = """
    010-23293293deuju010-23223293
    0111-3234123
    """
    # print(phone(s))
    print(verify(RE_CH, '輝'))
    print(verify(RE_PWD, 'dewu231_*'))
    

if __name__ == '__main__':
    main()      

用函數來實作

   

    

    

轉載于:https://www.cnblogs.com/louhui/p/8971497.html