Google's Python Class(六)——Python 正則表示式
正則表示式是一種用於匹配文字模式的強大的語言。這部分對正則表示式本身做了基本介紹,這些內容足以幫助我們做 Python 練習,並且介紹了在 Python 中如何使用正則表示式。Python 的 “re” 模組提供了對正則表示式的支援。
在 Python 中,一個典型的正則表示式搜尋可以寫成:
match = re.search(pat, str)
re.search() 方法的引數分別是一個正則表示式模式和一個字串,該方法根據模式搜尋字串。如果搜尋成功,search() 返回一個匹配的物件。否則返回 None。因此,該函式後面通常會緊跟著一個 if 語句來檢查搜尋是否成功,如下面的例子,根據 ‘word:’ 後面跟著 3 個字母(後面會詳細介紹)的模式去搜索:
str = 'an example word:cat!!'
match = re.search(r'word:\w\w\w', str)
# If-statement after search() tests if it succeeded
if match:
print 'found', match.group() ## 'found word:cat'
else:
print 'did not find'
程式碼 match = re.search(pat, str)
將搜尋結果儲存在一個名叫 “match” 的變數中。然後用 if 語句檢查 match——如果為 true,那麼搜尋成功並且 match.group() 表示匹配到的文字(例如,’word:cat’)。否則如果 match 為 false,那麼搜尋失敗,並且沒有匹配文字。
模式字串開頭的 ‘r’ 指定了 python 中“原始”(”raw”)字串,它防止字元被反斜槓轉義,這樣做對於正則表示式是很方便的(Java 非常需要這個特性!)。我建議你可以把在模式字串前面加上 ‘r’ 當成是一種習慣。
基本的模式
正則表示式的強大之處在於可以指定模式,而不僅僅是不變的字元。下面是匹配單個字元的最基本的模式:
a, X, 9, < —— 精確匹配它們自身的普通字元。元字元由於有特殊的意義,所以它們不會匹配自身:. ^ $ * + ? { [ ] \ | ( )(下面有詳細介紹)
.(一個句點) —— 匹配任意單個字元,除了換行符 ‘\n’
\w —— (小寫的 w)匹配一個“單詞”(”word”)字元:一個字母或者數字或者下劃線 [a-zA-Z0-9_]。注意到這裡的“單詞”(”word”)雖然有助於記憶,但是這裡只是匹配單個字元,不是整個單詞。\W(大寫的 W)匹配任意非單詞的字元。
\b —— 單詞和非單詞間的邊界
\s —— (小寫的 s)匹配一個空白字元——空格、換行符、回車、製表符、換頁 [ \n\r\t\f]。\S(大寫的 S)匹配任意一個非空白字元。
\t, \n, \r —— 製表、換行、回車
\d —— 十進位制數字 [0-9](一些老的正則表示式工具中不支援 \d,但是它們都支援 \w 和 \s)
^ = start, $ = end —— 匹配開頭或者結尾的字串
\ —— 抑制一個字元的“特殊性”。所以,例如,使用 . 匹配一個句點或者 \ 匹配一個斜槓。如果你不確定一個字元是否有特殊意義,例如 ‘@’,那麼你可以在該字元前面加上一個斜槓,\@,來確保它被當作一個字元。
基本的例子
正則表示式在一個字串中搜索模式的基本規則是:
搜尋是從字串的開頭到結尾進行,遇到第一個匹配項時停止
所有的模式必須要匹配到,但不是所有字串都要匹配
如果
match = re.search(pat, str)
成功,那麼匹配結果 match 不是 None,而 match.group() 是匹配到的文字
## Search for pattern 'iii' in string 'piiig'.
## All of the pattern must match, but it may appear anywhere.
## On success, match.group() is matched text.
match = re.search(r'iii', 'piiig') => found, match.group() == "iii"
match = re.search(r'igs', 'piiig') => not found, match == None
## . = any char but \n
match = re.search(r'..g', 'piiig') => found, match.group() == "iig"
## \d = digit char, \w = word char
match = re.search(r'\d\d\d', 'p123g') => found, match.group() == "123"
match = re.search(r'\w\w\w', '@@abcd!!') => found, match.group() == "abc"
重複
在模式中用 + 和 * 指定重複
+ —— 左邊的模式出現一次或多次,例如,’i+’ = 一個或者多個 i
* —— 左邊的模式出現 0 次或者多次
? —— 匹配左邊模式 0 次或者 1 次
最左的 & 最大的
首先 search 方法會查詢最左邊匹配模式的字串,然後它會嘗試查詢能夠匹配的儘可能多的字串——例如,+ 和 * 會盡可能多的匹配字元(+ 和 * 被稱為貪婪模式)
重複的例子
## i+ = one or more i's, as many as possible.
match = re.search(r'pi+', 'piiig') => found, match.group() == "piii"
## Finds the first/leftmost solution, and within it drives the +
## as far as possible (aka 'leftmost and largest').
## In this example, note that it does not get to the second set of i's.
match = re.search(r'i+', 'piigiiii') => found, match.group() == "ii"
## \s* = zero or more whitespace chars
## Here look for 3 digits, possibly separated by whitespace.
match = re.search(r'\d\s*\d\s*\d', 'xx1 2 3xx') => found, match.group() == "1 2 3"
match = re.search(r'\d\s*\d\s*\d', 'xx12 3xx') => found, match.group() == "12 3"
match = re.search(r'\d\s*\d\s*\d', 'xx123xx') => found, match.group() == "123"
## ^ = matches the start of string, so this fails:
match = re.search(r'^b\w+', 'foobar') => not found, match == None
## but without the ^ it succeeds:
match = re.search(r'b\w+', 'foobar') => found, match.group() == "bar"
郵件例子
假設你想從字串 ‘purple [email protected] monkey dishwasher’ 中找到郵件地址。我們將會使用這個例子來說明更多的正則表示式特性。下面的程式碼嘗試使用模式 r’\[email protected]\w+’:
str = 'purple [email protected] monkey dishwasher'
match = re.search(r'\[email protected]\w+', str)
if match:
print match.group() ## '[email protected]'
該搜尋獲取不到完整的郵件地址,因為 \w 不會匹配郵件地址中的 ‘-’ 或者 ‘.’。我們將會在下面使用正則表示式的特性來解決這個問題。
方括號
方括號可以用於表示一組字元,所以 [abc] 可以匹配 ‘a’ 或者 ‘b’ 或者 ‘c’。像 \w、\s 等這些特殊字元也可以在方括號裡面工作,除了小圓點(.)僅僅表示字面意義的小圓點。對於上述電子郵件的問題,可以通過模式 r’[\w.-][email protected][\w.-]+’ 來得到完整的郵件地址:
match = re.search(r'[\w.-][email protected][\w.-]+', str)
if match:
print match.group() ## '[email protected]'
(更多的方括號特性)你可以使用一個破折號來表示一個範圍,所以 [a-z] 匹配所有小寫字母。如果想要使用一個破折號又不想讓它指示一個範圍,那麼將破折號放到最後,例如,[abc-]。方括號開頭使用(^)表示反轉,所以 [^ab] 表示匹配除了 ‘a’ 或者 ‘b’ 意外的任意字元。
Group 方法提取資訊
正則表示式的 “group” 特性讓我們挑出匹配文字的部分內容。假設對於電子郵件那個問題,我們想要分開提取使用者名稱和 host。為了達到這個目的,在模式中使用者名稱和 host 兩邊新增小括號 (),即:r’([\w.-]+)@([\w.-]+)’。這種情況下,小括號不會改變模式所要匹配的東西,反而,小括號會在匹配文字中建立合乎邏輯的“組”(”groups”)。對於一個成功的搜尋,match.group(1) 的匹配文字對應左邊第 1 個小括號的內容,match.group(2) 的匹配文字對應左邊第 2 個小括號的內容。而 match.group() 還是完整的匹配文字。
str = 'purple [email protected] monkey dishwasher'
match = re.search(r'([\w.-]+)@([\w.-]+)', str)
if match:
print match.group() ## '[email protected]' (the whole match)
print match.group(1) ## 'alice-b' (the username, group 1)
print match.group(2) ## 'google.com' (the host, group 2)
正則表示式的一個通用流程是你為想要查詢的東西寫一個模式,然後新增小括號來提取你想要的部分。
findall
在 re 模組中,findall() 很可能是一個最強大的函式。上面我們使用 re.search() 來查詢一個模式中的第一個匹配內容。findall() 則查詢全部匹配的內容並且將匹配的結果以字串的形式放到一個列表中,每個字串代表一個匹配項。
## Suppose we have a text with many email addresses
str = 'purple [email protected], blah monkey [email protected] blah dishwasher'
## Here re.findall() returns a list of all the found email strings
emails = re.findall(r'[\w\.-][email protected][\w\.-]+', str) ## ['[email protected]', '[email protected]']
for email in emails:
# do something with each found email string
print email
findall With Files
對於檔案,你可能會習慣寫一個迴圈一行一行地遍歷檔案,然後為每行呼叫 findall()。然而,可以讓 findall() 為你做遍歷——這樣做更好!只需要將整個檔案文字傳進 findall(),然後用一個步驟讓它返回一個包含所有匹配內容的列表(f.read() 返回一個包含一個檔案裡所有文字的字串):
# Open file
f = open('test.txt', 'r')
# Feed the file text into findall(); it returns a list of all the found strings
strings = re.findall(r'some pattern', f.read())
findall and Groups
小括號 () 分組機制可以與 findall() 聯合起來使用。如果模式包含 2 個或更多的小括號分組,那麼不是返回一個由字串組成的列表,而是用 findall() 返回一個由元組組成的列表。每個元組代表一個模式匹配,並且在元組裡面是 group(1)、group(2)……資料。所以如果新增 2 個小括號分組到電子郵件模式中,那麼 findall() 會返回一個由元組組成的列表,每個長度為 2 的元組包含使用者名稱和 host,例如:(‘alice’, ‘google.com’)。
str = 'purple [email protected], blah monkey [email protected] blah dishwasher'
tuples = re.findall(r'([\w\.-]+)@([\w\.-]+)', str)
print tuples ## [('alice', 'google.com'), ('bob', 'abc.com')]
for tuple in tuples:
print tuple[0] ## username
print tuple[1] ## host
一旦你有了由元組組成的列表,你可以用迴圈來為每個元組做一些計算。如果模式沒有小括號,那麼 findall() 會返回一個像之前的例子中由找到的字串組成的列表。如果模式包含一對小括號,那麼 findall() 會返回由對應該單組的字串組成的列表。(模糊可選特性:有時在模式中會有括號 ()用於分組,但是你不想提取分組的內容。在這種情況下,在括號的開頭寫上 ?:,例如,(?: ),那個左括號就不會被算作一個分組結果。即非捕獲匹配,在不需要捕獲只需要指定分組的地方就可以使用)。
RE 工作流和除錯
正則表示式模式將大量的含義打包進幾個字元裡面,但是它們是如此緊密,使得你可以花費大量的時間去除錯你的模式。設定你的執行時,使得你可以執行一個模式並且很容易地列印它匹配到的內容,例如,可以在一個小的測試文字中執行這個模式,並且用 findall() 打印出結果。如果模式匹配不到東西,嘗試弱化模式,刪掉一部分從而得到大量的匹配結果。當它匹配不到東西,由於沒有實際的內容用於查詢,你不能繼續做任何處理。當匹配結果太多時,你可以漸漸地縮小範圍來找到你想要的。
選項
re 模組裡面的函式用選項來修改模式匹配的行為。選項標誌被當作附加引數新增到 search() 或者 findall() 等函式中,例如,re.search(pat, str, re.IGNORECASE)。
IGNORECASE —— 在匹配中不區分大小寫,即 ‘a’ 可以匹配 ‘a’ 和 ‘A’。
DOTALL —— 允許小圓點 (.) 匹配換行符 —— 通常小圓點匹配除了換行符的任意字元。這會使你犯錯 —— 你會認為 .* 匹配所有字元,但是預設它不會越過一行的末尾。注意到 \s(空格)包括換行符,所以如果你想匹配一連串可能包含換行符的空格,那麼使用 \s* 即可。
MULTILINE —— 一個由很多行組成的字串,允許用 ^ 和 $ 來匹配每行的開頭和結尾。通常
^/$
只會匹配整個字串的開頭和結尾。
貪婪與非貪婪(可選)
這一節課介紹了一種更高階的正則表示式技術。
假設有一組帶有標籤的文字:<b>foo</b> and <i>so on</i>
。
假設你嘗試用模式 ‘(<.*>)’ 去匹配每個標籤 —— 它首先會匹配什麼?
結果可能會讓人感到驚訝,但是 .* 貪婪的一面導致它匹配了整個字串 ‘<b>foo</b> and <i>so on</i>
‘。這裡的問題是 .* 會盡可能多地匹配字元,而不是在遇到第一個 > 的時候就停止(又名為“貪婪”)。
此時,你可以在末尾新增一個 ?,如 .*? 或者 .+?,將它們程式設計非貪婪。現在它們會盡可能快地停止匹配。所以模式 ‘(<.*?>)
’ 只會獲取 ‘<b>
’ 作為第一個匹配結果,而 ‘</b>
’ 作為第二個匹配結果,並且依次獲取每個 <..> 對。你常常會使用 .*? ,然後馬上查詢具體的標誌(這裡是 >)來強制 .*? 的結束。
*? 擴充套件起源於 Perl,而包含 Perl 擴充套件的正則表示式被稱為相容 Perl 的正則表示式庫(Perl Compatible Regular Expressions —— pcre)。Python 包含 pcre 的支援。很多命令列工具等會有一個標誌來表示是否支援 pcre 模式。
一種更老的卻又被廣泛使用的技術使用方括號風格來用程式碼實現 “all of these chars except stopping at X” 這個想法。對於上面的模式,可以使用 [^>]* 來跳過那些不是 > 的字元(方括號開頭的 ^ “反轉”,使得它匹配任意除了括號裡面的字元)。
替換(可選)
re.sub(pat, replacement, str) 函式搜尋一個給定字串中所有模式的例項,並且替換它們。字串 replacement 可以包括 ‘\1’、’\2’,即引用 group(1)、group(2) 等等從原始匹配文字中獲得的文字。
下面的例子搜尋所有電子郵件地址,並且保持使用者名稱 (\1) 不變,改變 host 為 yo-yo-dyne.com。
str = 'purple [email protected], blah monkey [email protected] blah dishwasher'
## re.sub(pat, replacement, str) -- returns new string with all replacements,
## \1 is group(1), \2 group(2) in the replacement
print re.sub(r'([\w\.-]+)@([\w\.-]+)', r'\[email protected]', str)
## purple [email protected], blah monkey [email protected] blah dishwasher
練習
相關推薦
Google's Python Class(六)——Python 正則表示式
正則表示式是一種用於匹配文字模式的強大的語言。這部分對正則表示式本身做了基本介紹,這些內容足以幫助我們做 Python 練習,並且介紹了在 Python 中如何使用正則表示式。Python 的 “re” 模組提供了對正則表示式的支援。 在 Python 中
自學python爬蟲(四)Requests+正則表示式爬取貓眼電影
前言 學了requests庫和正則表示式之後我們可以做個簡單的專案來練練手咯!先附上專案GitHub地址,歡迎star和fork,也可以pull request哦~ 地址:https://github.com/zhangyanwei233/Maoyan100.git 正文開始哈哈哈
爬蟲入門系列(六):正則表示式完全指南(下)
爬蟲入門系列目錄: 正則表示式是一種更為強大的字串匹配、字串查詢、字串替換等操作工具。上篇講解了正則表示式的基本概念和語法以及re模組的基本使用方式,這節來詳細說說 re 模組作為 Python 正則表示式引擎提供了哪些便利性操作。 >>> import re
Google's Python Class(二)——Python 字串
Python 有一個內建的 string 類叫做 “str”,該類包含很多方便的特性(還有一個更老的模組叫 “string”,不過我們不會用到它)。String 常量可以被雙引號或者單引號包起來,不過通常會使用單引號。反斜線轉義符後面帶單引號和雙引號表示他們
Python基礎(六)--- Python爬蟲,Python整合Hbase,PythonWorldCount,Spark資料分析生成分析圖表
一、Python爬蟲 --------------------------------------------------- 1.測試 # -*- encoding=utf-8 -*- import urllib.request #
PHP系統(六)PHP正則表達式
php正則php正則表達式 正則表達式是一種描述字符串結果的語法規則,是一個特定的格式化模式,可以匹配、替換、截取匹配的字符串。常用的語言基本上都有正則表達式,如JavaScript、java等。其實,只有了解一種語言的正則使用,其他語言的正則使用起來,就相對簡單些。文本主要圍繞解決下面問題展開
jmeter教程(七):正則表示式簡介
在後面講關聯和斷言,都會涉及到正則表示式,那麼,就先簡單的介紹一下正則表示式吧。 正則表示式的定義,這裡就不說了,百度裡應該有。正則表示式可以做什麼?處理文字,也只能處理文字。正則表示式,也常被程式設計師戲稱為“火星文”,從這個稱謂可以看出,正則表示式很難看懂。難到什麼程式呢?當你寫完一個比較複
爬蟲入門系列(五):正則表示式完全指南(上)
爬蟲入門系列目錄: 正則表示式處理文字有如疾風掃秋葉,絕大部分程式語言都內建支援正則表示式,它應用在諸如表單驗證、文字提取、替換等場景。爬蟲系統更是離不開正則表示式,用好正則表示式往往能收到事半功倍的效果。 介紹正則表示式前,先來看一個問題,下面這段文字來自豆瓣的某個網頁連結,我對內容
Boost(五)——字串處理(二):正則表示式操作
正則表示式: 一些簡單的描述符: . 匹配除換行符以外的任意字元 \w 匹配字母或數字或下劃線或漢字 等價於 '[^A-Za-z0-9_]'。 \s 匹配任意的空白符 \d 匹配數字 \b 匹配單詞的開始或結束 ^ 匹配字串的開始 $ 匹配字串的結束 一、字
(基礎)Python3正則表示式
python正則表示式介紹: 佇列 介紹 在爬蟲的程式中用到了廣度優先順序演算法,該演算法用到了資料結構,當然你用list也可以實現佇列,但是效率不高。現在在此處介紹下: 在容器中有佇列:collection.deque #佇列簡單測試: from co
jmeter(四):正則表示式提取器
使用jmeter來測試時,經常會碰到需要上下文傳輸資料的情況,如登入後生成的token,在其他頁面的操作,都需傳入這個token。這時,怎麼實現資料傳輸就是我們要考慮的問題。 jmeter提供的後置處理器,如正則表示式提取器,可以很方便的在伺服器響應後,把響應中的資料提取出
Shell基礎(四):正則表示式、cut、awk、sed命令
前言: 正則表示式是描述字元排列和匹配模式的一種語法規則。主要用於字串的模式分割、匹配、查詢及替換。(主要為了模糊匹配) 1、正則表示式與萬用字元區別 ①萬用字元(* ? [])用來匹配符合條件的檔名
萬用字元(WildCard)與正則表示式(Regular Expression)
1.萬用字元(wildcard)就是萬用牌的意思 * 表示匹配任意長度的任意字元 ? 表示匹配一個任意字元 […]則表示匹配括號中列出的字元中的任意一個 [!..]表示不
IOS使用第三方工具(RegexKitLite)實現正則表示式
1、在寫正則表示式時:所有的’\’都需要轉義,即:’\\’; 2、在很多JS的正則表示式可能是這樣寫,如:’/^\d{1,400}$/’,但是這樣的表示式Objective-C中並不能識別,通過實際除錯得出,應將其寫為:’ ^\\d{1,400}$’(即:去掉表示式頭和尾的’/’)
Python練習(六)
素數 開關 Python練習(六)給一個數,判斷它是否是素數(質數): 除了1和它自身外,不能被小於它的正整數整除的就是素數。 簡化點就是:能整除,不是素數 不能整除,是素數可以參考另一篇《Python練習(三)》中有介紹如何計算出1-100之內的所有素數n
python學習(六)---文件操作
not game seek read 終端設備 fas uic med ear 文件操作文件操作流程 1、打開文件,得到文件句柄並賦值給一個變量 2、通過句柄對文件進行操作 3、關閉文件現有文件如下: Somehow, it seems the love I knew
python入門(六)裝飾器的理解
裝飾器裝飾器用於拓展原有函數功能的一種函數比如: def helloWorld(fun) def out() print ("======start========") fun() print ("
自學python爬蟲(六)PyQuery使用
一、概念 PyQuery庫也是很強大的網頁解析庫,適合熟悉Jquery的人使用,因為PyQuery和Jquery的API幾乎一模一樣。 二、詳細講解 1、初始化 1.1字串初始化 # 字串初始化 html = """ <div> <ul>
Python基礎(六)之 for 迴圈
全部測試程式碼、 #!/usr/bin/env python3 # _*_ conding:utf-8 _*_ #計算1+2+3 count=1+2+3 print('count--',count) #計算1+2+3+...+10; sum=0 for i in [1,2,
python學習(六)函式
實現特定功能的一坨程式碼,為了提高程式碼的複用性;用def定義,必須呼叫才會執行 入參的時候為形參(變數);呼叫時傳的為實參;在函式裡定義的變數為區域性變數,只能在函式中使用;return 返回值 函式中幾種引數:位置引數、預設值引數、可變引數(*args)、關鍵字引