Python正則表達式(更長的正則表達式示例)示例代碼
更長的正則表達式示例
我們現(xiàn)在將瀏覽一個深入的示列,它以不同的方式使用正則表達式來操作字符串。首先是一些實際上生成用于操作隨機數(shù)(但不是太隨機)的代碼。示例1-5 展示了gendata.py,這是一個生成數(shù)據(jù)集的腳本。盡管該程序只是將簡單地將生成的字符串集顯示到標準輸出,但是該輸出可以很容易重定向到測試文件。
示例1-5 用于正則表達式練習的數(shù)據(jù)生成器(gendata.py)
該腳本為正則表達式練習創(chuàng)建隨機數(shù)據(jù),然后將生成的數(shù)據(jù)輸出到屏幕。要將該程序移植到Python 3,僅需要將print 語句修改為函數(shù),將xrange()函數(shù)修改為range(),以及將sys.maxint 修改為sys.maxsize。
from random import randrange,choice
from string import ascii_lowercase as lc
from sys import maxint
from time import ctime
tlds=('com','edu','net','org','gov')
for i in xrange(randrange(5,11)):
dtint=randrange(maxint) #pick date
dtstr=ctime(dtint) #date string
llen=randrange(4,8) #login is shorter
login=''.join(choice(lc) for j in range(llen))
dlen=randrange(llen,13) #domain is longer
dom=''.join(choice(lc) for j in xrange(dlen))
print('%s::%s@%s.%s::%d-%d-%d' % (dtstr,login,
dom,choice(tlds),dtint,llen,dlen))該腳本生成擁有三個字段的字符串,由一對冒號或者一對雙冒號分隔。第一個字段是隨機(32 位)整數(shù),該整數(shù)將被轉(zhuǎn)換為一個日期。下一個字段是一個隨機生成的電子郵件地址。
最后一個字段是一個由單橫線(-)分隔的整數(shù)集。
運行這段代碼,我們將獲得以下輸出(讀者將會從此獲益頗多),并將該輸出在本地另存為redata.txt 文件。
Thu Jul 22 19:21:19 2004::izsp@dicqdhytvhv.edu::1090549279-4-11 Sun Jul 13 22:42:11 2008::zqeu@dxaibjgkniy.com::1216014131-4-11 Sat May 5 16:36:23 1990::fclihw@alwdbzpsdg.edu::641950583-6-10 Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8 Thu Jun 26 19:08:59 2036::ugxfugt@jkhuqhs.net::2098145339-7-7 Tu e Apr 10 01:04:45 2012::zkwaq@rpxwmtikse.com::1334045085-5-10
讀者或者可能會辨別出來,但是來自該程序的輸出是為正則表達式處理做準備的。后續(xù)將逐
行解釋,我們將實現(xiàn)一些正則表達式來操作這些數(shù)據(jù),以及為本章末尾的練習留下很多內(nèi)容。
匹配字符串
對于后續(xù)的練習,為正則表達式創(chuàng)建寬松和約束性的版本。建議讀者在一個簡短的應用中測試這些正則表達式,該應用利用之前所展示的示例文件redata.txt(或者使用通過運行g(shù)endata.py 生成的數(shù)據(jù))。當做練習時,讀者將需要再次使用該數(shù)據(jù)。
在將正則表達式放入應用中之前,為了測試正則表達式,我們將導入re 模塊,然后將redata.txt 中的一個示例行賦給字符串變量data。如下所示,這些語句在所有展示的示例中都是常量。
>>> import re >> > data = 'Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'
在第一個示例中,我們將創(chuàng)建一個正則表達式來提取(僅僅)數(shù)據(jù)文件redata.txt 中每一行時間戳中一周的幾天。我們將使用下面的正則表達式。
"^ Mon|^Tue|^Wed|^Thu|^Fri|^Sat|^Sun"
該示例需要字符串以列出的7 個字符串中的任意一個開頭(“^”正則表達式中的脫字符)。
如果我們將該正則表達式“翻譯”成自然語言,讀起來就會像這樣:“字符串應當以“Mon”,“Tue”,. . . ,“Sat”或者“Sun”開頭。
換句話說,如果按照如下所示的方式對日期字符串分組,我們就可以使用一個脫字符來替換所有脫字符。
"^ (Mon|Tue|Wed|Thu|Fri|Sat|Sun)"
括住字符串集的圓括號意思是:這些字符串中的一個將會有一次成功匹配。這是我們一開始就使用的“友好的”正則表達式版本,該版本并沒有使用圓括號。如下所示,在這個修改過的正則表達式版本中,可以以子組的方式來訪問匹配字符串。
>>> patt = '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)'
>>> m = re.match(patt, data)
>>> m.group() # entire match
'Thu'
>>> m.group(1) # subgroup 1
'Thu'
>>> m.groups() # all subgroups
(' Thu',)
我們在該示例所實現(xiàn)的這個特性可能看起來并不是革命性的,但是在下一個示例或者作為正則表達式的一部分提供額外數(shù)據(jù)來實現(xiàn)字符串匹配操作的任何地方,它確定有它的獨到之處,即使這些字符并不是你所感興趣字符的一部分。
以上兩個正則表達式都是非常嚴格的,尤其是要求一個字符串集。這可能在一個國際化的環(huán)境中并不能良好地工作,因為所在的環(huán)境中會使用當?shù)氐娜掌诤涂s寫。一個寬松的正則表達式將為:^\w{3}。該正則表達式僅僅需要一個以三個連續(xù)字母數(shù)字字符開頭的字符串。
再一次,將正則表達式轉(zhuǎn)換為正常的自然語言:脫字符^表示“作為起始”,\w 表示任意單個字母數(shù)字字符,{3}表示將會有3 個連續(xù)的正則表達式副本,這里使用{3}來修飾正則表達式。
再一次,如果想要分組,就必須使用圓括號,例如^(\w{3})。
>>> patt = '^(\w{3})'
>>> m = re.match(patt, data)
>>> if m is not None: m.group()
...
'Thu'
>>> m.group(1)
'T hu'
注意,正則表達式^(\w){3}是錯誤的。當{3}在圓括號中時,先匹配三個連續(xù)的字母數(shù)字字符,然后表示為一個分組。但是如果將{3}移到外部,它就等效于三個連續(xù)的單個字母數(shù)字字符。
>>> patt = '^(\w){3}'
>>> m = re.match(patt, data)
>>> if m is not None: m.group()
...
'Thu'
>>> m.group(1)
'u '
當我們訪問子組1 時,出現(xiàn)字母“u”的原因是子組1 持續(xù)被下一個字符替換。換句話說,m.group(1)以字母“T”作為開始,然后變?yōu)?ldquo;h”,最終被替換為“u”。這些是單個字母數(shù)字字符的三個獨立(并且重疊)分組,與一個包含三個連續(xù)字母數(shù)字字符的單獨分組相反。
在下一個(而且是最后)的示例中,我們將創(chuàng)建一個正則表達式來提取redata.txt 每一行的末尾所發(fā)現(xiàn)的數(shù)字字段。
搜索與匹配……還有貪婪
然而,在創(chuàng)建任何正則表達式之前,我們就意識到這些整數(shù)數(shù)據(jù)項位于數(shù)據(jù)字符串的末尾。這就意味著我們需要選擇使用搜索還是匹配。發(fā)起一個搜索將更易于理解,因為我們確切知道想要查找的內(nèi)容(包含三個整數(shù)的數(shù)據(jù)集),所要查找的內(nèi)容不是在字符串的起始部分,也不是整個字符串。如果我們想要實現(xiàn)匹配,就必須創(chuàng)建一個正則表達式來匹配整個行,然后使用子組來保存想要的數(shù)據(jù)。要展示它們之間的差別,就需要先執(zhí)行搜索,然后實現(xiàn)匹配,以展示使用搜索更適合當前的需要。
因為我們想要尋找三個由連字符分隔的整數(shù),所以可以創(chuàng)建自己的正則表達式來說明這一需求:\d±\d±\d+。該正則表達式的含義是,“任何數(shù)值的數(shù)字(至少一個)后面跟著一個連字符,然后是多個數(shù)字、另一個連字符,最后是一個數(shù)字集。”我們現(xiàn)在將使用search()來測試該正則表達式:
>>> patt = '\d+-\d+-\d+' >>> re.search(patt, data).group() # entire match '1 171590364-6-8'
一個匹配嘗試失敗了,為什么呢?因為匹配從字符串的起始部分開始,需要被匹配的數(shù)值位于字符串的末尾。我們將不得不創(chuàng)建另一個正則表達式來匹配整個字符串。但是可以使用惰性匹配,即使用“.+”來表明一個任意字符集跟在我們真正感興趣的部分之后。
patt = '.+\d+-\d+-\d+' >>> re.match(patt, data).group() # entire match 'T hu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'
該正則表達式效果非常好,但是我們只想要末尾的數(shù)字字段,而并不是整個字符串,因此不得不使用圓括號對想要的內(nèi)容進行分組。
>>> patt = '.+(\d+-\d+-\d+)' >>> re.match(patt, data).group(1) # subgroup 1 '4 -6-8'
發(fā)生了什么?我們將提取1171590364-6-8,而不僅僅是4-6-8。第一個整數(shù)的其余部分在哪兒?問題在于正則表達式本質(zhì)上實現(xiàn)貪婪匹配。這就意味著對于該通配符模式,將對正則表達式從左至右按順序求值,而且試圖獲取匹配該模式的盡可能多的字符。在之前的示例中,使用
“.+”獲取從字符串起始位置開始的全部單個字符,包括所期望的第一個整數(shù)字段。\d+僅僅需要一個數(shù)字,因此將得到“4”,其中.+匹配了從字符串起始部分到所期望的第一個數(shù)字的全部內(nèi)容:“Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::117159036”,如圖1-2 所示。

其中的一個方案是使用“非貪婪”操作符“?”。讀者可以在“*”、“+”或者“?”之后使用該操作符。該操作符將要求正則表達式引擎匹配盡可能少的字符。因此,如果在“.+”之10后放置一個“?”,我們將獲得所期望的結(jié)果,如圖1-3 所示。
>>> patt = '.+?(\d+-\d+-\d+)' >>> re.match(patt, data).group(1) # subgroup 1 '1171590364-6-8'

另一個實際情況下更簡單的方案,就是把“::”作為字段分隔符。讀者可以僅僅使用正則字符串strip(‘:: ‘)方法獲取所有的部分,然后使用strip(’-’)作為另一個橫線分隔符,就能夠獲取最初想要查詢的三個整數(shù)。現(xiàn)在,我們不想先選擇該方案,因為這就是我們?nèi)绾螌⒆址旁谝黄?,以使用gendata.py 作為開始!
最后一個示例:假定我們僅想取出三個整數(shù)字段中間的那個整數(shù)。如下所示,這就是實現(xiàn)的方法(使用一個搜索,這樣就不必匹配整個字符串):-(\d+)-。嘗試該模式,將得到以下內(nèi)容。
>>> patt = '-(\d+)-' >>> m = re.search(patt, data) >>> m.group() # entire match '-6-' >>> m.group(1) # subgroup 1 '6 '
本章幾乎沒有涉及正則表達式的強大功能,在有限的篇幅里面我們不可能做到。然而,我們希望已經(jīng)向讀者提供了足夠有用的介紹性信息,使讀者能夠掌握這個強有力的工具,并融入到自己的編程技巧里面。建議讀者閱讀參考文檔以獲取在Python 中如何使用正則表達式
的更多細節(jié)。對于想要更深入研究正則表達式的讀者,建議閱讀由 Jeffrey E. F. Friedl.編寫的Mastering Regular Expressions。
總結(jié)
到此這篇關(guān)于Python正則表達式的文章就介紹到這了,更多相關(guān)Python正則表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python爬取網(wǎng)頁數(shù)據(jù)到保存到csv
大家好,本篇文章主要講的是python爬取網(wǎng)頁數(shù)據(jù)到保存到csv,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2022-01-01
Python使用PyMuPDF(fitz)處理PDF文檔的操作指南
在Python中,PyMuPDF 是一個功能強大且高效的庫,用于處理多種文檔格式,尤其是PDF,它基于 MuPDF 引擎,提供了豐富的功能,包括文檔的讀取、寫入、修改、渲染和文本提取等,以下是一些關(guān)鍵用法和示例代碼,需要的朋友可以參考下2025-07-07
Python中出現(xiàn)IndentationError:unindent does not match any outer
今天在網(wǎng)上copy的一段代碼,代碼很簡單,每行看起來該縮進的都縮進了,運行的時候出現(xiàn)了如下錯誤,IndentationError: unindent does not match any outer indentation level,如果看起來縮進正常所有tab與空格混用就會出現(xiàn)這個問題2019-01-01
Python優(yōu)化技巧之利用ctypes提高執(zhí)行速度
ctypes是Python的一個外部庫,提供和C語言兼容的數(shù)據(jù)類型,可以很方便地調(diào)用C DLL中的函數(shù)。今天我們就來詳細探討下ctypes庫的使用技巧2016-09-09
Python編程scoketServer實現(xiàn)多線程同步實例代碼
這篇文章主要介紹了Python編程scoketServer實現(xiàn)多線程同步實例代碼,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
django中使用POST方法獲取POST數(shù)據(jù)
這篇文章主要介紹了django中使用POST方法獲取POST數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08

