在學習re.split函數的處理過程中,發現執行如下語句及返回與老猿預想的不一致:
>>> re.split('\W*','Hello,world')
['', 'H', 'e', 'l', 'l', 'o', '', 'w', 'o', 'r', 'l', 'd', '']
而老猿期望的是[’’, ‘Hello’, ‘’, ‘world’, ‘’],結果差異很大。
我們再看使用組模式匹配的結果:
>>> re.split('(\W*)','Hello,world')
['', '', 'H', '', 'e', '', 'l', '', 'l', '', 'o', ',', '', '', 'w', '', 'o', '', 'r', '', 'l', '', 'd', '', '']
也不是老猿期望的:[’’,‘Hello’, ‘,’, ‘world’, ‘’]。
將上述匹配模式中的\W*改成\W+,來看看效果:
>>> re.split('\W+','Hello,world')
['Hello', 'world']
>>> re.split('(\W+)','Hello,world')
['Hello', ',', 'world']
>>>
這個效果與老猿預想一致。在老猿預想的里面,使用“\W*”和“\W+”的區別應該就是在搜索文本頭和尾的處理上二者有區別,“\W*”應該比“\W+”只多頭和尾匹配的空字符串,畢竟二者都是貪婪模式,只是“\W*允許0次重復”。為什么執行結果卻大相徑庭呢?
經過仔細思考,老猿認為正則的匹配過程有關,在貪婪模式下,老猿理解上述正則表達式的匹配基本處理方法如下:
- 所有匹配過程都是從搜索文本當前匹配到的位置(為了后續方便稱為當前匹配位置)開始的,首次匹配就從搜索文本位置0開始,其后真正匹配過程每匹配一個字符匹配位置加一(前視斷言、后視斷言等不消耗搜索文本的方法除外);
- 每次匹配時,都是從搜索文本當前匹配位置開始以類似切片的機制開始匹配:
1)切片的開始位置為當前位置,切片的結束位置從當前位置開始逐一增加(假設當前位置為n,則第一次切片類似n:n,也就是空字符串);
2)每次切片都會驗證是否切片后的內容能否匹配當前模式,如果能匹配,切片結束位置加一,按此順序處理,直到切片不能匹配為止;
3)如果當前切片不能匹配,則匹配的搜索文本子串就是前一個切片(不妨稱為匹配切片),如果前一個切片的起止位置相同則為空字符串,如果起始位置大於結束位置則沒有匹配到,否則就是正常匹配;
4)匹配到空串或正常子串都認為匹配成功,當前匹配位置=匹配切片結束位置+1。
這樣我們回頭來看使用“\W*”和“\W+”來匹配單詞“Hello”的過程,由於每個字符當前位置的0長切片都為空字符串,他們滿足“\W*”匹配要求,而下個長度為1的切片是字母字符,不能滿足匹配的要求,因此會認為單詞的每個字母之間都會被空字符串分割,如果不接受這樣的結果,使用”\W+”來匹配就可以。
關於閱讀本文所需要使用的基礎知識請參考:
1、關於“\W*”和“\W+”的含義請參考《第11.15節 Python正則表達式轉義符定義的特殊序列》;
2、關於切片請參考《第3章 Python的數據類型 第3.1節 功能強大的 Python序列概述》;
3、關於正則表達式貪婪模式請參考:《第11.9節 Python正則表達式的貪婪模式和非貪婪模式》及《轉:正則表達式之 貪婪與非貪婪模式詳解》;
4、關於re.split請參考《第11.22節Python 中re模塊的split函數》。
老猿Python,跟老猿學Python!
博客地址:https://blog.csdn.net/LaoYuanPython
請大家多多支持,點贊、評論和加關注!謝謝!