1. 程式人生 > >正則表達式詳解

正則表達式詳解

保存 響應 das mda blank dal 不支持 忽略大小寫 不同之處

正則表達式是一個很強大的字符串處理工具,幾乎任何關於字符串的操作都可以使用正則表達式來完成,作為一個爬蟲工作者,每天和字符串打交道,正則表達式更是不可或缺的技能,正則表達式的在不同的語言中使用方式可能不一樣,不過只要學會了任意一門語言的正則表達式用法,其他語言中大部分也只是換了個函數的名稱而已,本質都是一樣的。下面,我來介紹一下python中的正則表達式是怎麽使用的。

  首先,python中的正則表達式大致分為以下幾部分:

    1. 元字符
    2. 模式
    3. 函數
    4. re 內置對象用法
    5. 分組用法
    6. 環視用法

  所有關於正則表達式的操作都使用 python 標準庫中的 re 模塊。

一、元字符 (參見 python 模塊 re 文檔)

    • . 匹配任意字符(不包括換行符)
    • ^ 匹配開始位置,多行模式下匹配每一行的開始
    • $ 匹配結束位置,多行模式下匹配每一行的結束
    • * 匹配前一個元字符0到多次
    • + 匹配前一個元字符1到多次
    • ? 匹配前一個元字符0到1次
    • {m,n} 匹配前一個元字符m到n次
    • \\ 轉義字符,跟在其後的字符將失去作為特殊元字符的含義,例如\\.只能匹配.,不能再匹配任意字符
    • [] 字符集,一個字符的集合,可匹配其中任意一個字符
    • | 邏輯表達式 或 ,比如 a|b 代表可匹配 a 或者 b
    • (...) 分組,默認為捕獲,即被分組的內容可以被單獨取出,默認每個分組有個索引,從 1 開始,按照"("的順序決定索引值
    • (?iLmsux) 分組中可以設置模式,iLmsux之中的每個字符代表一個模式,用法參見 模式 I
    • (?:...) 分組的不捕獲模式,計算索引時會跳過這個分組
    • (?P<name>...) 分組的命名模式,取此分組中的內容時可以使用索引也可以使用name
    • (?P=name) 分組的引用模式,可在同一個正則表達式用引用前面命名過的正則
    • (?#...) 註釋,不影響正則表達式其它部分,用法參見 模式 I
    • (?=...) 順序肯定環視,表示所在位置右側能夠匹配括號內正則
    • (?!...) 順序否定環視,表示所在位置右側不能匹配括號內正則
    • (?<=...) 逆序肯定環視,表示所在位置左側能夠匹配括號內正則
    • (?<!...) 逆序否定環視,表示所在位置左側不能匹配括號內正則
    • (?(id/name)yes|no) 若前面指定id或name的分區匹配成功則執行yes處的正則,否則執行no處的正則
    • \number 匹配和前面索引為number的分組捕獲到的內容一樣的字符串
    • \A 匹配字符串開始位置,忽略多行模式
    • \Z 匹配字符串結束位置,忽略多行模式
    • \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_]

二、模式

    • I IGNORECASE, 忽略大小寫的匹配模式, 樣例如下
    • s = hello World!
      
      regex = re.compile("hello world!", re.I)
      print regex.match(s).group()
      #output> ‘Hello World!‘
      
      #在正則表達式中指定模式以及註釋
      regex = re.compile("(?#註釋)(?i)hello world!")
      print regex.match(s).group()
      #output> ‘Hello World!‘

    • L LOCALE, 字符集本地化。這個功能是為了支持多語言版本的字符集使用環境的,比如在轉義符\w,在英文環境下,它代表[a-zA-Z0-9_],即所以英文字符和數字。如果在一個法語環境下使用,缺省設置下,不能匹配"é" 或 "ç"。加上這L選項和就可以匹配了。不過這個對於中文環境似乎沒有什麽用,它仍然不能匹配中文字符。
    • M MULTILINE,多行模式, 改變 ^ 和 $ 的行為
    • s = ‘‘‘first line
      second line
      third line‘‘‘
      
      # ^
      regex_start = re.compile("^\w+")
      print regex_start.findall(s)
      # output> [‘first‘]
      
      regex_start_m = re.compile("^\w+", re.M)
      print regex_start_m.findall(s)
      # output> [‘first‘, ‘second‘, ‘third‘]
      
      #$
      regex_end = re.compile("\w+$")
      print regex_end.findall(s)
      # output> [‘line‘]
      
      regex_end_m = re.compile("\w+$", re.M)
      print regex_end_m.findall(s)
      # output> [‘line‘, ‘line‘, ‘line‘]

    • S  DOTALL,此模式下 ‘.‘ 的匹配不受限制,可匹配任何字符,包括換行符
    • s = ‘‘‘first line
      second line
      third line‘‘‘
      #
      regex = re.compile(".+")
      print regex.findall(s)
      # output> [‘first line‘, ‘second line‘, ‘third line‘]
      
      # re.S
      regex_dotall = re.compile(".+", re.S)
      print regex_dotall.findall(s)
      # output> [‘first line\nsecond line\nthird line‘]

    • X VERBOSE,冗余模式, 此模式忽略正則表達式中的空白和#號的註釋,例如寫一個匹配郵箱的正則表達式
      email_regex = re.compile("[\w+\.][email protected][a-zA-Z\d]+\.(com|cn)")
      
      email_regex = re.compile("""[\w+\.]+  # 匹配@符前的部分
                                  @  # @符
                                  [a-zA-Z\d]+  # 郵箱類別
                                  \.(com|cn)   # 郵箱後綴  """, re.X)

    • U UNICODE,使用 \w, \W, \b, \B 這些元字符時將按照 UNICODE 定義的屬性.

正則表達式的模式是可以同時使用多個的,在 python 裏面使用按位或運算符 | 同時添加多個模式

如 re.compile(‘‘, re.I|re.M|re.S)

每個模式在 re 模塊中其實就是不同的數字

print re.I
# output> 2
print re.L
# output> 4
print re.M
# output> 8
print re.S
# output> 16
print re.X
# output> 64
print re.U
# output> 32

三、函數 (參見 python 模塊 re 文檔)

python 的 re 模塊提供了很多方便的函數使你可以使用正則表達式來操作字符串,每種函數都有它自己的特性和使用場景,熟悉之後對你的工作會有很大幫助

    • compile(pattern, flags=0)

給定一個正則表達式 pattern,指定使用的模式 flags 默認為0 即不使用任何模式,然後會返回一個 SRE_Pattern (參見第四小節 re 內置對象用法) 對象

regex = re.compile(".+")
print regex
# output> <_sre.SRE_Pattern object at 0x00000000026BB0B8>

這個對象可以調用其他函數來完成匹配,一般來說推薦使用 compile 函數預編譯出一個正則模式之後再去使用,這樣在後面的代碼中可以很方便的復用它,當然大部分函數也可以不用 compile 直接使用,具體見 findall 函數

s = ‘‘‘first line
second line
third line‘‘‘
#
regex = re.compile(".+")
# 調用 findall 函數
print regex.findall(s)
# output> [‘first line‘, ‘second line‘, ‘third line‘]
# 調用 search 函數
print regex.search(s).group()
# output> first lin

    • escape(pattern)

轉義 如果你需要操作的文本中含有正則的元字符,你在寫正則的時候需要將元字符加上反斜扛 \ 去匹配自身, 而當這樣的字符很多時,寫出來的正則表達式就看起來很亂而且寫起來也挺麻煩的,這個時候你可以使用這個函數,用法如下

s = ".+\d123"
#
regex_str = re.escape(".+\d123")
# 查看轉義後的字符
print regex_str
# output> \.\+\\d123

# 查看匹配到的結果
for g in re.findall(regex_str, s):
    print g
# output> .+\d123

    • findall(pattern, string, flags=0)

參數 pattern 為正則表達式, string 為待操作字符串, flags 為所用模式,函數作用為在待操作字符串中尋找所有匹配正則表達式的字串,返回一個列表,如果沒有匹配到任何子串,返回一個空列表。

s = ‘‘‘first line
second line
third line‘‘‘

# compile 預編譯後使用 findall
regex = re.compile("\w+")
print regex.findall(s)
# output> [‘first‘, ‘line‘, ‘second‘, ‘line‘, ‘third‘, ‘line‘]

# 不使用 compile 直接使用 findall
print re.findall("\w+", s)
# output> [‘first‘, ‘line‘, ‘second‘, ‘line‘, ‘third‘, ‘line‘]

    • finditer(pattern, string, flags=0)

參數和作用與 findall 一樣,不同之處在於 findall 返回一個列表, finditer 返回一個叠代器(參見http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html ), 而且叠代器每次返回的值並不是字符串,而是一個 SRE_Match (參見 第四小節 re 內置對象用法) 對象,這個對象的具體用法見 match 函數。

s = ‘‘‘first line
second line
third line‘‘‘

regex = re.compile("\w+")
print regex.finditer(s)
# output> <callable-iterator object at 0x0000000001DF3B38>
for i in regex.finditer(s):
    print i
# output> <_sre.SRE_Match object at 0x0000000002B7A920>
#         <_sre.SRE_Match object at 0x0000000002B7A8B8>
#         <_sre.SRE_Match object at 0x0000000002B7A920>
#         <_sre.SRE_Match object at 0x0000000002B7A8B8>
#         <_sre.SRE_Match object at 0x0000000002B7A920>
#         <_sre.SRE_Match object at 0x0000000002B7A8B8>

    • match(pattern, string, flags=0)

使用指定正則去待操作字符串中尋找可以匹配的子串, 返回匹配上的第一個字串,並且不再繼續找,需要註意的是 match 函數是從字符串開始處開始查找的,如果開始處不匹配,則不再繼續尋找,返回值為 一個 SRE_Match (參見 第四小節 re 內置對象用法) 對象,找不到時返回 None

技術分享圖片
s = ‘‘‘first line
second line
third line‘‘‘

# compile
regex = re.compile("\w+")
m = regex.match(s)
print m
# output> <_sre.SRE_Match object at 0x0000000002BCA8B8>
print m.group()
# output> first

# s 的開頭是 "f", 但正則中限制了開始為 i 所以找不到
regex = re.compile("^i\w+")
print regex.match(s)
# output> None
技術分享圖片
    • purge()

當你在程序中使用 re 模塊,無論是先使用 compile 還是直接使用比如 findall 來使用正則表達式操作文本,re 模塊都會將正則表達式先編譯一下, 並且會將編譯過後的正則表達式放到緩存中,這樣下次使用同樣的正則表達式的時候就不需要再次編譯, 因為編譯其實是很費時的,這樣可以提升效率,而默認緩存的正則表達式的個數是 100, 當你需要頻繁使用少量正則表達式的時候,緩存可以提升效率,而使用的正則表達式過多時,緩存帶來的優勢就不明顯了 (參考 《python re.compile對性能的影響》http://blog.trytofix.com/article/detail/13/), 這個函數的作用是清除緩存中的正則表達式,可能在你需要優化占用內存的時候會用到。

    • search(pattern, string, flags=0)

函數類似於 match,不同之處在於不限制正則表達式的開始匹配位置

技術分享圖片
s = ‘‘‘first line
second line
third line‘‘‘

# 需要從開始處匹配 所以匹配不到 
print re.match(‘i\w+‘, s)
# output> None

# 沒有限制起始匹配位置
print re.search(‘i\w+‘, s)
# output> <_sre.SRE_Match object at 0x0000000002C6A920>

print re.search(‘i\w+‘, s).group()
# output> irst
技術分享圖片
    • split(pattern, string, maxsplit=0, flags=0)

參數 maxsplit 指定切分次數, 函數使用給定正則表達式尋找切分字符串位置,返回包含切分後子串的列表,如果匹配不到,則返回包含原字符串的一個列表

技術分享圖片
s = ‘‘‘first 111 line
second 222 line
third 333 line‘‘‘

# 按照數字切分
print re.split(‘\d+‘, s)
# output> [‘first ‘, ‘ line\nsecond ‘, ‘ line\nthird ‘, ‘ line‘]

# \.+ 匹配不到 返回包含自身的列表
print re.split(‘\.+‘, s, 1)
# output> [‘first 111 line\nsecond 222 line\nthird 333 line‘]

# maxsplit 參數
print re.split(‘\d+‘, s, 1)
# output> [‘first ‘, ‘ line\nsecond 222 line\nthird 333 line‘]
技術分享圖片

    • sub(pattern, repl, string, count=0, flags=0)

替換函數,將正則表達式 pattern 匹配到的字符串替換為 repl 指定的字符串, 參數 count 用於指定最大替換次數

技術分享圖片
s = "the sum of 7 and 9 is [7+9]."

# 基本用法 將目標替換為固定字符串
print re.sub(‘\[7\+9\]‘, ‘16‘, s)
# output> the sum of 7 and 9 is 16.

# 高級用法 1 使用前面匹配的到的內容 \1 代表 pattern 中捕獲到的第一個分組的內容
print re.sub(‘\[(7)\+(9)\]‘, r‘\2\1‘, s)
# output> the sum of 7 and 9 is 97.


# 高級用法 2 使用函數型 repl 參數, 處理匹配到的 SRE_Match 對象
def replacement(m):
    p_str = m.group()
    if p_str == ‘7‘:
        return ‘77‘
    if p_str == ‘9‘:
        return ‘99‘
    return ‘‘
print re.sub(‘\d‘, replacement, s)
# output> the sum of 77 and 99 is [77+99].


# 高級用法 3 使用函數型 repl 參數, 處理匹配到的 SRE_Match 對象 增加作用域 自動計算
scope = {}
example_string_1 = "the sum of 7 and 9 is [7+9]."
example_string_2 = "[name = ‘Mr.Gumby‘]Hello,[name]"

def replacement(m):
    code = m.group(1)
    st = ‘‘
    try:
        st = str(eval(code, scope))
    except SyntaxError:
        exec code in scope
    return st

# 解析: code=‘7+9‘
#       str(eval(code, scope))=‘16‘
print re.sub(‘\[(.+?)\]‘, replacement, example_string_1)
# output> the sum of 7 and 9 is 16.

# 兩次替換 # 解析1: code="name = ‘Mr.Gumby‘" # eval(code) # raise SyntaxError # exec code in scope # 在命名空間 scope 中將 "Mr.Gumby" 賦給了變量 name # 解析2: code="name" # eval(name) 返回變量 name 的值 Mr.Gumby print re.sub(‘\[(.+?)\]‘, replacement, example_string_2) # output> Hello,Mr.Gumby
技術分享圖片
    • subn(pattern, repl, string, count=0, flags=0)

作用與函數 sub 一樣, 唯一不同之處在於返回值為一個元組,第一個值為替換後的字符串,第二個值為發生替換的次數

    • template(pattern, flags=0)

這個吧,咋一看和 compile 差不多,不過不支持 +、?、*、{} 等這樣的元字符,只要是需要有重復功能的元字符,就不支持,查了查資料,貌似沒人知道這個函數到底是幹嘛的...

  四、re 內置對象用法

    • SRE_Pattern 這個對象是一個編譯後的正則表達式,編譯後不僅能夠復用和提升效率,同時也能夠獲得一些其他的關於正則表達式的信息

屬性:

  • flags 編譯時指定的模式
  • groupindex 以正則表達式中有別名的組的別名為鍵、以該組對應的編號為值的字典,沒有別名的組不包含在內。
  • groups 正則表達式中分組的數量
  • pattern 編譯時用的正則表達式 技術分享圖片
    s = ‘Hello, Mr.Gumby : 2016/10/26‘
    p = re.compile(‘‘‘(?:        # 構造一個不捕獲分組 用於使用 |
                  (?P<name>\w+\.\w+)    # 匹配 Mr.Gumby
                  |     # 或
                  (?P<no>\s+\.\w+) # 一個匹配不到的命名分組
                  )
                  .*? # 匹配  : 
                  (\d+) # 匹配 2016
                  ‘‘‘, re.X)
    
    #
    print p.flags
    # output> 64
    print p.groupindex
    # output> {‘name‘: 1, ‘no‘: 2}
    print p.groups
    # output> 3
    print p.pattern
    # output> (?:        # 構造一個不捕獲分組 用於使用 |
    #              (?P<name>\w+\.\w+)    # 匹配 Mr.Gumby
    #              |     # 或
    #              (?P<no>\s+\.\w+) # 一個匹配不到的命名分組
    #              )
    #              .*? # 匹配  : 
    #              (\d+) # 匹配 2016
    技術分享圖片

函數:可使用 findall、finditer、match、search、split、sub、subn 等函數

    • SRE_Match 這個對象會保存本次匹配的結果,包含很多關於匹配過程以及匹配結果的信息

屬性:

  • endpos 本次搜索結束位置索引
  • lastgroup 本次搜索匹配到的最後一個分組的別名
  • lastindex 本次搜索匹配到的最後一個分組的索引
  • pos 本次搜索開始位置索引
  • re 本次搜索使用的 SRE_Pattern 對象
  • regs 列表,元素為元組,包含本次搜索匹配到的所有分組的起止位置
  • string 本次搜索操作的字符串 技術分享圖片
    s = ‘Hello, Mr.Gumby : 2016/10/26‘
    m = re.search(‘, (?P<name>\w+\.\w+).*?(\d+)‘, s)
    # 本次搜索的結束位置索引
    print m.endpos
    # output> 28

    # 本次搜索匹配到的最後一個分組的別名
    # 本次匹配最後一個分組沒有別名
    print m.lastgroup
    # output> None

    # 本次搜索匹配到的最後一個分組的索引
    print m.lastindex
    # output> 2

    # 本次搜索開始位置索引
    print m.pos
    # output> 0

    # 本次搜索使用的 SRE_Pattern 對象
    print m.re
    # output> <_sre.SRE_Pattern object at 0x000000000277E158>

    # 列表,元素為元組,包含本次搜索匹配到的所有分組的起止位置 第一個元組為正則表達式匹配範圍
    print m.regs
    # output> ((7, 22), (7, 15), (18, 22))

    # 本次搜索操作的字符串
    print m.string
    # output> Hello, Mr.Gumby : 2016/10/26
    技術分享圖片

函數:

  • end([group=0]) 返回指定分組的結束位置,默認返回正則表達式所匹配到的最後一個字符的索引
  • expand(template) 根據模版返回相應的字符串,類似與 sub 函數裏面的 repl, 可使用 \1 或者 \g<name> 來選擇分組
  • group([group1, ...]) 根據提供的索引或名字返回響應分組的內容,默認返回 start() 到 end() 之間的字符串, 提供多個參數將返回一個元組
  • groupdict([default=None]) 返回 返回一個包含所有匹配到的命名分組的字典,沒有命名的分組不包含在內,key 為組名, value 為匹配到的內容,參數 default 為沒有參與本次匹配的命名分組提供默認值
  • groups([default=None]) 以元組形式返回每一個分組匹配到的字符串,包括沒有參與匹配的分組,其值為 default
  • span([group]) 返回指定分組的起止位置組成的元組,默認返回由 start() 和 end() 組成的元組
  • start([group]) 返回指定分組的開始位置,默認返回正則表達式所匹配到的第一個字符的索引 技術分享圖片
    s = ‘Hello, Mr.Gumby : 2016/10/26‘
    m = re.search(‘‘‘(?:        # 構造一個不捕獲分組 用於使用 |
                  (?P<name>\w+\.\w+)    # 匹配 Mr.Gumby
                  |     # 或
                  (?P<no>\s+\.\w+) # 一個匹配不到的命名分組
                  )
                  .*? # 匹配  : 
                  (\d+) # 匹配 2016
                  ‘‘‘,
                  s, re.X)
    
    # 返回指定分組的結束位置,默認返回正則表達式所匹配到的最後一個字符的索引
    print m.end()
    # output> 22
    
    # 根據模版返回相應的字符串,類似與 sub 函數裏面的 repl, 可使用 \1 或者 \g<name> 來選擇分組
    print m.expand("my name is \\1")
    # output> my name is Mr.Gumby
    
    # 根據提供的索引或名字返回響應分組的內容,默認返回 start() 到 end() 之間的字符串, 提供多個參數將返回一個元組
    print m.group()
    # output> Mr.Gumby : 2016
    print m.group(1,2)
    # output> (‘Mr.Gumby‘, None)
    
    # 返回 返回一個包含所有匹配到的命名分組的字典,沒有命名的分組不包含在內,key 為組名, value 為匹配到的內容,參數 default 為沒有參與本次匹配的命名分組提供默認值
    print m.groupdict(‘default_string‘)
    # output> {‘name‘: ‘Mr.Gumby‘, ‘no‘: ‘default_string‘}
    
    # 以元組形式返回每一個分組匹配到的字符串,包括沒有參與匹配的分組,其值為 default
    print m.groups(‘default_string‘)
    # output> (‘Mr.Gumby‘, ‘default_string‘, ‘2016‘)
    
    # 返回指定分組的起止未知組成的元組,默認返回由 start() 和 end() 組成的元組
    print m.span(3)
    # output> (18, 22)
    
    # 返回指定分組的開始位置,默認返回正則表達式所匹配到的第一個字符的索引
    print m.start(3)
    # output> 18
    技術分享圖片

五、分組用法

python 的正則表達式中用小括號 "(" 表示分組,按照每個分組中前半部分出現的順序 "(" 判定分組的索引,索引從 1 開始,每個分組在訪問的時候可以使用索引,也可以使用別名

技術分享圖片
s = ‘Hello, Mr.Gumby : 2016/10/26‘
p = re.compile("(?P<name>\w+\.\w+).*?(\d+)(?#comment)")
m = p.search(s)

# 使用別名訪問
print m.group(‘name‘)
# output> Mr.Gumby
# 使用分組訪問
print m.group(2)
# output> 2016
技術分享圖片

有時候可能只是為了把正則表達式分組,而不需要捕獲其中的內容,這時候可以使用非捕獲分組

技術分享圖片
s = ‘Hello, Mr.Gumby : 2016/10/26‘
p = re.compile("""
                (?:  # 非捕獲分組標誌 用於使用 |
                    (?P<name>\w+\.\w+)
                    |
                    (\d+/)
                )
                """, re.X)
m = p.search(s)
# 使用非捕獲分組
# 此分組將不計入 SRE_Pattern 的 分組計數
print p.groups
# output> 2

# 不計入 SRE_Match 的分組
print m.groups()
# output> (‘Mr.Gumby‘, None)
技術分享圖片

如果你在寫正則的時候需要在正則裏面重復書寫某個表達式,那麽你可以使用正則的引用分組功能,需要註意的是引用的不是前面分組的 正則表達式 而是捕獲到的 內容,並且引用的分組不算在分組總數中.

技術分享圖片
s = ‘Hello, Mr.Gumby : 2016/2016/26‘
p = re.compile("""
                (?:  # 非捕獲分組標誌 用於使用 |
                    (?P<name>\w+\.\w+)
                    |
                    (\d+/)
                )
                .*?(?P<number>\d+)/(?P=number)/
                """, re.X)
m = p.search(s)
# 使用引用分組
# 此分組將不計入 SRE_Pattern 的 分組計數
print p.groups
# output> 3

# 不計入 SRE_Match 的分組
print m.groups()
# output> (‘Mr.Gumby‘, None, ‘2016‘)

# 查看匹配到的字符串
print m.group()
# output> Mr.Gumby : 2016/2016/
技術分享圖片

六、環視用法

環視還有其他的名字,例如 界定、斷言、預搜索等,叫法不一。

環視是一種特殊的正則語法,它匹配的不是字符串,而是 位置,其實就是使用正則來說明這個位置的左右應該是什麽或者應該不是什麽,然後去尋找這個位置。

環視的語法有四種,見第一小節元字符,基本用法如下。

技術分享圖片
s = ‘Hello, Mr.Gumby : 2016/10/26  Hello,r.Gumby : 2016/10/26‘

# 不加環視限定
print re.compile("(?P<name>\w+\.\w+)").findall(s)
# output> [‘Mr.Gumby‘, ‘r.Gumby‘]

# 環視表達式所在位置 左邊為 "Hello, "
print re.compile("(?<=Hello, )(?P<name>\w+\.\w+)").findall(s)
# output> [‘Mr.Gumby‘]

# 環視表達式所在位置 左邊不為 ","
print re.compile("(?<!,)(?P<name>\w+\.\w+)").findall(s)
# output> [‘Mr.Gumby‘]

# 環視表達式所在位置 右邊為 "M"
print re.compile("(?=M)(?P<name>\w+\.\w+)").findall(s)
# output> [‘Mr.Gumby‘]

# 環視表達式所在位置 右邊不為 r
print re.compile("(?!r)(?P<name>\w+\.\w+)").findall(s)
# output> [‘Mr.Gumby‘]
技術分享圖片

高級一些的例子參見《正則基礎之——環視(Lookaround)》(http://www.cnblogs.com/kernel0815/p/3375249.html)

參考文章:

《Python正則表達式指南》(http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html)

Python 正則式學習筆記 》(http://blog.csdn.net/whycadi/article/details/2011046)

正則表達式詳解