Python網絡爬蟲(九)——re

正則表達式

  • 正則表達式(Regular Expression)是一種文本模式,包括普通字符(如 a-z)和特殊字符(元字符)
  • 正則表達式使用單個字符串來描述,用來匹配一系列滿足某個句法規則的字符串

匹配規則

匹配某個字符串

import re

text = 'hello'
ret = re.match('he',text)
print(ret.group())

結果爲:

he

匹配任意字符(.)

import re

text = "ab"
ret = re.match('.',text)
print(ret.group())

結果爲:

a

上邊的結果中匹配到了第一個字符,但是使用 . 不能匹配到換行符。

import re

text = "\nab"
ret = re.match('.',text)
print(ret.group())

結果爲:

AttributeError: 'NoneType' object has no attribute 'group'

匹配任意數字(\d)

import re

text = "123"
ret = re.match('\d',text)
print(ret.group())

結果爲:

1

匹配任意非數字(\D)

import re

text = "abc"
ret = re.match('\D',text)
print(ret.group())

結果爲:

a

如果匹配的字符爲數字,則會報錯:

import re

text = "123"
ret = re.match('\D',text)
print(ret.group())

結果爲:

AttributeError: 'NoneType' object has no attribute 'group'

匹配空白字符(\s)

import re

text = "\t"
ret = re.match('\s',text)
print(ret.group())

結果爲:


匹配非空白字符(\S)

import re

text = "abc"
ret = re.match('\S',text)
print(ret.group())

 結果爲:

a

匹配a-z、A-Z、0-9和下劃線(\w)

import re

text = "_abc"
ret = re.match('\w',text)
print(ret.group())

結果爲:

_

如果能匹配到的字符不是上述的字符之一,則也會報 AttributeError 錯誤。

匹配與(\w)相反的字符(\W)

import re

text = "+-*/"
ret = re.match('\W',text)
print(ret.group())

結果爲:

+

如果能匹配到的字符是(\w)能匹配到的字符,則也會報 AttributeError 錯誤。

[]

匹配滿足中括號中的任一項

import re

text = "86-8642354"
ret = re.match('[\d\-]+',text)
print(ret.group())

結果爲:

86-8642354

匹配 0 個或者任意多個字符(*)

import re

text = "86-8642354"
ret = re.match('\d*',text)
print(ret.group())

結果爲:

86

匹配 1 個或者多個字符(+)

import re

text = "hello"
ret = re.match('\w+',text)
print(ret.group())

結果爲:

hello

匹配 1 個或者多個字符要求至少能夠匹配一個字符,如果一個都匹配不到,則會報錯。

import re

text = "+hello"
ret = re.match('\w+',text)
print(ret.group())

結果爲:

AttributeError: 'NoneType' object has no attribute 'group'

匹配 0 次或 1 次字符(?)

import re

text = "abc"
ret = re.match('\w?',text)
print(ret.group())

結果爲:

a

匹配 m 個字符({m})

import re

text = "abc"
ret = re.match('\w{3}',text)
print(ret.group())

結果爲:

abc

匹配 m-n 個字符({m,n})

import re

text = "abcd"
ret = re.match('\w{2,5}',text)
print(ret.group())

結果爲:

abcd

以...起始(^)

import re

text = "hello"
ret = re.match('^h',text)
print(ret.group())

如果 ^ 是在中括號中,則表示取反:

import re

text = "hello"
ret = re.match('[^\W]',text)
print(ret.group())

結果爲:

h

以...結束($)

import re

text = "hello"
ret = re.search('o$',text)
print(ret.group())

結果爲:

o

匹配多個表達式或者字符串

import re

text = "world"
ret = re.search('hello|world',text)
print(ret.group())

結果爲:

world

貪婪模式和非貪婪模式

  • 貪婪模式:正則表達式會盡量多的匹配字符,默認爲貪婪模式
  • 非貪婪模式:正則表達式會盡量少的匹配字符
import re

text = "abcdefg"
ret = re.match('\w',text)
print(ret.group())
ret = re.match('\w+',text)
print(ret.group())
ret = re.match('\w+?',text)
print(ret.group())

結果爲:

a
abcdefg
a

上邊第一次匹配到了 a,然後使用 + 匹配到了所有字符,此時就是貪婪模式,而在 + 後邊多跟一個 ? 就取消了 + 的作用,變成了非貪婪模式。

轉義字符

從上邊可以看出,有些字符被用於了進行字符串匹配,因此如果想要匹配這些字符,就需要使用 \ 對這些字符進行轉義。

import re

text = "1+1=2"
ret = re.match('1\+1=2',text)
print(ret.group())

 結果爲:

1+1=2

原生字符串

那麼如果需要匹配 \,就需要:

import re

text = "apple \c"
print(text)
ret = re.search('\\\c',text)
# ret = re.search('\\\\c',text)
print(ret.group())

因爲 python 中的 \ 可以用來進行轉義,而正則表達式中的 \ 則是專門用來進行轉義的,因此 search 中的 '\\\c' 會首先在 python 中被轉義爲 '\\c',然後將之傳遞到 re 中,在 re 中又會將 '\\c' 轉義爲 '\c'。如果是 '\\\\c' 則會將 '\\\\c' 轉義爲 '\\c',然後將之傳遞到 re 中,在 re 中又會將 '\\c' 轉義爲 '\c'。

這種轉換關係無疑是很麻煩的,而原生表達式可以解決這個問題。

原生字符串在字符串前加 r 表達:

import re

text = "apple \c"
print(text)
ret = re.search(r'\\c',text)
print(ret.group())

使用這種形式則不需要再經過 python 轉義,直接將 r 後的字符全部傳遞到正則表達式中。

re

python 中自帶了 re 模塊,該模塊提供了對正則表達式的支持。

常用函數

match

def match(pattern, string, flags=0):
    """Try to apply the pattern at the start of the string, returning
    a match object, or None if no match was found."""
    return _compile(pattern, flags).match(string)

從開始位置進行匹配,匹配成功則返回匹配到的字符,反之則返回 None。

search

def 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."""
    return _compile(pattern, flags).search(string)

在字符串中匹配滿足條件的字符,匹配成功則返回匹配到的字符,反之則返回 None。

group

在正則表達式中,可以對匹配到的字符進行分組,分組使用圓括號的形式:

  • group:返回整個滿足條件的字符串,等價於 group(0)
  • groups:返回子組,索引從 1 開始
  • group(1):返回第一個子組,可以傳入多個
import re

text = "abc def ghi"
ret = re.search('(abc)\s(def)\s(ghi)',text)
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
print(ret.groups())
print(ret.group(1,2,3))

結果爲:

abc def ghi
abc
def
ghi
('abc', 'def', 'ghi')
('abc', 'def', 'ghi')

findall

def findall(pattern, string, flags=0):
    """Return a list of all non-overlapping matches in the string.

    If one or more capturing groups are present in the pattern, return
    a list of groups; this will be a list of tuples if the pattern
    has more than one group.

    Empty matches are included in the result."""
    return _compile(pattern, flags).findall(string)

找出所有符合匹配條件的字符串,此時返回的是一個 list:

import re

text = "abc abc abc"
ret = re.match('abc',text)
print(type(ret))
ret = re.findall('abc',text)
print(type(ret))
print(ret)

結果爲:

<class '_sre.SRE_Match'>
<class 'list'>
['abc', 'abc', 'abc']

sub

def sub(pattern, repl, string, count=0, flags=0):
    """Return the string obtained by replacing the leftmost
    non-overlapping occurrences of the pattern in string by the
    replacement repl.  repl can be either a string or a callable;
    if a string, backslash escapes in it are processed.  If it is
    a callable, it's passed the match object and must return
    a replacement string to be used."""
    return _compile(pattern, flags).sub(repl, string, count)

進行字符串替換,此時返回的是 str 類型:

import re

text = "abc abc abc"
ret = re.sub('abc','def',text)
print(type(ret))
print(text)
print(ret)

結果爲:

<class 'str'>
abc abc abc
def def def

split

def split(pattern, string, maxsplit=0, flags=0):
    """Split the source string by the occurrences of the pattern,
    returning a list containing the resulting substrings.  If
    capturing parentheses are used in pattern, then the text of all
    groups in the pattern are also returned as part of the resulting
    list.  If maxsplit is nonzero, at most maxsplit splits occur,
    and the remainder of the string is returned as the final element
    of the list."""
    return _compile(pattern, flags).split(string, maxsplit)

使用正則表達式進行分隔,此時返回的是一個 list:

import re

text = "abc abc abc"
ret = re.split('\s',text)
print(type(ret))
print(ret)

結果爲:

<class 'list'>
['abc', 'abc', 'abc']

compile

def compile(pattern, flags=0):
    "Compile a regular expression pattern, returning a pattern object."
    return _compile(pattern, flags)

如果某些正則表達式的使用頻率較高,可以使用 compile 進行編譯,使用的時候直接調用,這樣能夠提高執行的效率。

import re

text = "birthday is 2000/12/13"
r = re.compile(r"""
                \d+ # 年份
                / # 分隔符
                \d+ # 月份
                / # 分隔符
                \d+ # 日
                """,re.VERBOSE)
ret = re.search(r,text)
print(ret.group())

結果爲:

2000/12/13

上述 compile 中添加了 flags=re.VERBOSE,爲正則表達式添加了註釋。

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