正規表示式(三):pythonre模組

登天螞蟻發表於2018-07-10

以下示例所使用 python 版本為: 3.7

python 提供 re 模組,來滿足正規表示式的使用。在開始介紹 re 模組之前,首先說明一下兩個小內容:

  1. 轉義字元

轉義字元作用是使得字元失去原本的意思,去表示另外一個作用。例如字元 d 表示一個普通的字元 d, 加 轉義後 d 表示數字,字元 s 經轉義後,s 表示空白字元。

如果要匹配轉義符號 本身,則需要表達為 \ 。而在程式語言中要表達兩個轉義符號 \,則需要對每個轉義符號進行轉義,即形式為 \\,需要四個轉義符號才能完成用於匹配一個轉義符號 的正規表示式。

為了減弱轉義字元使用上的麻煩,能夠將使用者的注意力集中在正規表示式的編寫上,這裡推薦所有的正規表示式開頭使用 r 字元開頭,表示正則內容作為原始字串輸入到 re 模組的使用中。即程式設計環境中 r`\` 直接作為正規表示式使用,來完成對字元 的匹配。

示例:

import re

reg = r`\`
str = `\`    #轉義符號,str實際值為

if re.match(reg,str):
    print(`match {}`.format(str))
------------------------
執行結果:
match 
  1. Pattern、Match物件

在re模組中使用正規表示式完成字串處理有兩種方式:

  • 在 python 中可以直接使用 re 模組生成 Match 物件,完成字串處理。
    示例:
import re

reg = r`abc`
str = `abc`

mattern = re.match(reg,str)
print(mattern .group())
------------------------
執行結果:
abc
  • 使用 re 模組生成 Pattern 物件,然後使用 Pattern 物件生成 Match 物件,完成字串處理。
    示例:
import re

reg = r`abc`
str = `abc`

pattern = re.compile(reg)
match = pattern.match(str)
print(match.group())
------------------------
執行結果:
abc

這兩種方式執行效果基本一樣,觀察 re 模組原始碼:

模組: Python37Lib
e.py

# --------------------------------------------------------------------
# public interface

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)

def compile(pattern, flags=0):                #第二種方式
    "Compile a regular expression pattern, returning a Pattern object."
    return _compile(pattern, flags)

# --------------------------------------------------------------------
# internals

_cache = {}  # ordered!

_MAXCACHE = 512
def _compile(pattern, flags):
    # internal: compile pattern
    if isinstance(flags, RegexFlag):
        flags = flags.value
    try:
        return _cache[type(pattern), pattern, flags]         #從快取字典中查詢
    except KeyError:
        pass
    if isinstance(pattern, Pattern):
        if flags:
            raise ValueError(
                "cannot process flags argument with a compiled pattern")
        return pattern
    if not sre_compile.isstring(pattern):
        raise TypeError("first argument must be string or compiled pattern")
    p = sre_compile.compile(pattern, flags)
    if not (flags & DEBUG):
        if len(_cache) >= _MAXCACHE:
            # Drop the oldest item
            try:
                del _cache[next(iter(_cache))]
            except (StopIteration, RuntimeError, KeyError):
                pass
        _cache[type(pattern), pattern, flags] = p         #新增到快取字典中
    return p

觀察原始碼可知, re 模組提供的 compile 函式和 match 函式,都需要先通過 _compile(pattern, flags) 函式生成一個 Pattern 物件,區別在於 match 函式直接在生成 Pattern 物件後呼叫了 match 函式。
觀察 _compile(pattern, flags) 函式體可知,首先會從快取字典中查詢是否已經存在 Pattern 物件,存在則返回,不存在則生成該 Pattern 物件,新增到快取字典後返回。

由此可知,直接使用 re 模組的 match 函式來生成 Match 物件,和使用 re 模組的 compile 函式生成 Pattern 物件,然後再利用 match 函式生成 Match 物件完成字串處理,這兩種方式都是首先呼叫 _compile(pattern, flags) 函式生成一個Pattern物件,然後再使用該 Pattern 物件的 match 函式生成 Match 物件。

所以兩種方式基本相同,區別只在於當 Pattern 物件多次使用時,第一種方式會存在多次查詢快取操作,且快取字典容量是有限制的,超出後會刪除最先新增的 Pattern 物件,所以推薦所有的正則中都使用構造的 Pattern 物件來完成字串處理。

下面列出 Pattern 物件中使用到的函式:
函式名 作用
match(string, pos=0, endpos=-1) 在指定範圍內,從指定的起始位置開始匹配,得到匹配物件則返回
search(string, pos=0, endpos=-1) 在指定範圍內,從任意位置開始匹配,得到匹配物件則返回
findall(string, pos=0, endpos=-1) 在指定範圍內,返回所有匹配結果構成的列表
finditer(string, pos=0, endpos=-1) 在指定範圍內,返回所有匹配物件構成的迭代器
split(string, maxsplit=0) 按照指定的分割次數,返回分割得到的結果列表
sub(repl, string, count=0) 按照指定的替換規則和替換次數,返回替換後的結果
subn(repl, string, count=0) 按照指定的替換規則和替換次數,返回替換後的結果和替換次數構成的元組
  • match 函式

match 函式返回指定範圍內,從指定起始位置開始匹配到的物件。使用過程中只有三點需要注意一下:
1. 可以指定匹配的範圍,預設範圍是 0 到 len(str)
2. 匹配是從指定的起始位置開始的,也就是固定了開始位置
3. 匹配成功則返回,也就是隻返回一個匹配物件

示例:

import re

reg = r`d`
pattern = re.compile(reg)

str1 = `a1b2c3`

match1 = pattern.match(str1)
match2 = pattern.match(str1,1)

print(`match1 = {}`.format(match1))
if match1:
    print(`match1 matched = {}`.format(match1.group()))

print(`match2 = {}`.format(match2))
if match2:
    print(`match2 matched = {}`.format(match2.group()))
執行結果:
match1 = None
match2 = <re.Match object; span=(1, 2), match=`1`>
match2 matched = 1
  • search 函式

search 函式返回指定範圍內,從任意起始位置開始匹配到的物件。使用過程中只有三點需要注意一下:
1. 可以指定匹配的範圍,預設範圍是 0 到 len(str)
2. 匹配是從範圍內的任意起始位置開始的,也就是不固定開始位置
3. 匹配成功則返回,也就是隻返回一個匹配物件

示例:

import re

reg = r`d`
pattern = re.compile(reg)

str1 = `a1b2c3`

match1 = pattern.search(str1)

print(`match1 = {}`.format(match1))
if match1:
    print(`match1 matched = {}`.format(match1.group()))
執行結果:
match1 = <re.Match object; span=(1, 2), match=`1`>
match1 matched = 1

比較 match 和 search 函式的使用:兩個函式都是一次匹配,得到結果則返回 (None 或 Match 物件),區別在於 match 函式從指定的起始位置開始匹配,search 函式從指定範圍內的任意位置開始。

  • findall 函式

findall 函式返回指定範圍內,所有匹配結果構成的列表。使用過程中只有兩點需要注意一下:
1. 可以指定匹配的範圍,預設範圍是 0 到 len(str)
2. 返回的是一個列表,元素是 str 物件,而非 Match 物件

示例:

import re

reg = r`d`
pattern = re.compile(reg)

str1 = `a1b2c3`

match1 = pattern.findall(str1)

print(`match1 = {}`.format(match1))
for element in match1:
    print(`element = {}`.format(element))
執行結果:
match1 = [`1`, `2`, `3`]
element = 1
element = 2
element = 3
  • finditer 函式

finditer 函式返回指定範圍內,所有匹配物件構成的迭代器。使用過程中只有兩點需要注意一下:
1. 可以指定匹配的範圍,預設範圍是 0 到 len(str)
2. 返回的是一個迭代器,元素是 Match 物件

示例:

import re

reg = r`d`
pattern = re.compile(reg)

str1 = `a1b2c3`

match1 = pattern.finditer(str1)

print(`match1 = {}`.format(match1))
for element in match1:
    print(`element = {}`.format(element.group()))
執行結果:
match1 = <callable_iterator object at 0x0000000002CA0550>
element = 1
element = 2
element = 3

比較 findall 和 finditer 函式的使用:兩個函式都是獲取所有匹配內容,區別在於 findall 函式返回的是一個列表,元素型別是 str,finditer 函式返回的是一個迭代器,元素型別是 Match 。

  • split 函式

split 函式返回根據指定分割次數,分割後得到的結果列表。使用過程中只有兩點需要注意一下:
1. 可以指定分割次數,預設值 0 表示全分割
2. 返回的是一個列表,元素是 str 物件

示例:

import re

reg = r`d`
pattern = re.compile(reg)

str1 = `a1b2c3`

match1 = pattern.split(str1)

print(`match1 = {}`.format(match1))
for element in match1:
    print(`element = {}`.format(element))
執行結果:
match1 = [`a`, `b`, `c`, ``]
element = a
element = b
element = c
element = 
  • sub 函式

sub 函式根據指定替換規則和替換次數,返回替換後內容。使用過程中只有三點需要注意一下:
1. 可以指定替換次數,預設值 0 表示全替換
2. 返回的是一個 str 物件
3. 指定的替換規則可以是 str 物件,可以是一個函式,也可以是分組的引用

示例:

import re

def fun(match):
    return match.group()[::-1]

reg = r`(d)(d)`
pattern = re.compile(reg)

str1 = `a12b34c56`

match1 = pattern.sub(`__`,str1)
match2 = pattern.sub(fun,str1)
match3 = pattern.sub(r`21`,str1)

print(`match1 = {}`.format(match1))
print(`match2 = {}`.format(match2))
print(`match3 = {}`.format(match3))
執行結果:
match1 = a__b__c__
match2 = a21b43c65
match3 = a21b43c65
  • subn 函式

subn 函式根據指定替換規則和替換次數,返回替換後內容和替換次數構成的元組。使用過程中只有三點需要注意一下:
1. 可以指定替換次數,預設值 0 表示全替換
2. 返回的是一個 str 物件和 int 物件構成的元組
3. 指定的替換規則可以是 str 物件,可以是一個函式,也可以是分組的引用

示例:

import re

def fun(match):
    return match.group()[::-1]

reg = r`(d)(d)`
pattern = re.compile(reg)

str1 = `a12b34c56`

match1 = pattern.subn(`__`,str1,1)
match2 = pattern.subn(`__`,str1,2)


print(`match1 = {}`.format(match1))
print(`match2 = {}`.format(match2))
執行結果:
match1 = (`a__b34c56`, 1)
match2 = (`a__b__c56`, 2)

比較 sub 和 subn 函式的使用:兩個函式都是替換匹配內容,區別在於 sub 函式返回的是一個 str 物件,subn 函式返回的是替換後 str 物件和替換次數 int 物件構成的元組。

下面列出 Match 物件中常到的函式:
函式名 作用
group(*args) 返回指定的分組匹配的結果
groups(default=None) 返回所有分組匹配結果構成的元組
span(group=0) 返回由指定分組匹配結果區間的首尾兩個下標值構成的元組
start(group=0) 返回指定分組匹配結果區間的首下標值
end(group=0) 返回指定分組匹配結果區間的尾下標值
  • group、groups、span、start、end 函式

以上這幾個函式作為常用函式,使用方式較為簡單:
1. group:返回指定分組匹配的內容,引數為零或者預設值時,返回整個正規表示式匹配結果;引數為多個分組時,返回分組匹配結果構成的元組
2. groups:返回分組匹配結果構成的元組
3. span:返回指定分組匹配結果區間的首尾兩個下標值(左閉右開)構成的元組,預設情況下匹配整個正規表示式匹配結果的首尾兩個下標值
4. start:返回指定分組匹配結果區間的首下標
5. end:返回指定分組匹配結果區間的尾下標

示例:

import re

reg = r`(d)(d)`
pattern = re.compile(reg)

str1 = `a12b`

match1 = pattern.search(str1)

print(`group 1 = {}`.format(match1.group(1)))
print(`span 1 = {}`.format(match1.span(1)))
print(`start 1 = {}`.format(match1.start(1)))
print(`end 1 = {}`.format(match1.end(1)),end=`

`)

print(`group 2 = {}`.format(match1.group(2)))
print(`span 2 = {}`.format(match1.span(2)))
print(`start 2 = {}`.format(match1.start(2)))
print(`end 2 = {}`.format(match1.end(2)),end=`

`)

print(`groups = {}`.format(match1.groups()))
print(`span = {}`.format(match1.span()))
print(`start = {}`.format(match1.start()))
print(`end = {}`.format(match1.end()),end=`

`)

print(`group 1,2 = {}`.format(match1.group(1,2)))
執行結果:
group 1 = 1
span 1 = (1, 2)
start 1 = 1
end 1 = 2

group 2 = 2
span 2 = (2, 3)
start 2 = 2
end 2 = 3

groups = (`1`, `2`)
span = (1, 3)
start = 1
end = 3

group 1,2 = (`1`, `2`)
Pattern 用作模式處理,Match 用作分組結果提取

比較以上 Pattern 和 Match 兩種物件的使用方式,可以發現 Pattern 物件作用如其名稱所示,是一種體現正規表示式規則的物件,也就是體現為一種文字模式。其所提供的諸多函式,如: find、search、match 等等,都是拿自身的規則以不同的方式去處理目標文字。而 Match 物件則是對分組結果的操作,Match 物件提供的函式則都是對結果以不同方式的提取,如:groups、span等,獲取匹配分組結果的各項資料。


相關文章