Python正則表達(dá)式教程:常用文本處理技巧
介紹:
正則表達(dá)式用于識別模式(pattern)是否存在于給定的字符(字符串)序列中。它們有助于處理文本數(shù)據(jù),這通常是涉及文本挖掘的數(shù)據(jù)科學(xué)項目的先決條件。您一定遇到過一些正則表達(dá)式的應(yīng)用程序:它們在服務(wù)器端用于在注冊過程中驗證電子郵件地址或密碼的格式,用于解析文本數(shù)據(jù)文件以查找,替換或刪除某些字符串等。
內(nèi)容:
正則表達(dá)式非常強(qiáng)大,在本教程中,您將學(xué)習(xí)在Python中使用它們。您將涵蓋以下主題:
- Python中的正則表達(dá)式
- 基本字符:普通字符
- 通配符:特殊字符
- 重復(fù)次數(shù)
- 使用正則表達(dá)式進(jìn)行分組
- 貪婪vs非貪婪匹配
- re Python庫 --- search() 與 match()
Python中的正則表達(dá)式
- 導(dǎo)入re模塊
在Python中,re模塊支持正則表達(dá)式。使用以下命令導(dǎo)入此模塊:
- Import re
- 基本模式:普通字符
您可以使用普通字符輕松解決Python中的許多基本模式。普通字符是最簡單的正則表達(dá)式。它們完全匹配,并且在正則表達(dá)式語法中沒有特殊含義。
示例為" A"," a"," X"," 5"。
普通字符可用于執(zhí)行簡單的完全匹配:
- >>>Import re
- >>>pattern = r"Cookie"
- >>>sequence = "Cookie"
- >>>if re.match(pattern, sequence):
- >>> print("Match!")
- >>>else:
- >>> print("Not a match!")
- Match!
match()如果文本與模式匹配,則該函數(shù)返回匹配對象。否則返回None。
不過,現(xiàn)在讓我們關(guān)注普通字符!您是否注意到r模式的開頭Cookie?
這稱為原始字符串文字。它更改了字符串文字的解釋方式。這樣的文字會按其出現(xiàn)時進(jìn)行存儲。
例如,\當(dāng)前綴為a時只是一個反斜杠,r而不是被解釋為轉(zhuǎn)義序列。您將看到帶有特殊字符的含義。有時,語法涉及反斜杠轉(zhuǎn)義的字符,并且為了防止將這些字符解釋為轉(zhuǎn)義序列,請使用原始r前綴。在本示例中,您實際上并不需要它,但是使用它來保持一致性是一種很好的做法。
- 通配符:特殊字符
特殊字符是與正則表達(dá)式不匹配但在正則表達(dá)式中使用時實際上具有特殊含義的字符。
最廣泛使用的特殊字符是:
- . -匹配除換行符以外的任何單個字符。
- re.search(r'Co.k.e', 'Cookie').group()
- 'Cookie'
該group()函數(shù)返回與匹配的字符串re。稍后您將更詳細(xì)地看到此功能。
- \w - 小寫w。匹配任何單個字母,數(shù)字或下劃線。
- re.search(r'Co\wk\we', 'Cookie').group()
- 'Cookie'
- \W - 大寫w。匹配不屬于\ w的任何字符(小寫w)。
- re.search(r'C\Wke', 'C@ke').group()
- 'C@ke'
- \s - 小寫字母s。匹配單個空格字符,例如:空格,換行符,制表符,返回值。
- re.search(r'Eat\scake', 'Eat cake').group()
- 'Eat cake'
- \S - 大寫字母s。匹配不屬于\ s(小寫s)的任何字符。
- re.search(r'Cook\Se', 'Cookie').group()
- 'Cookie'
- \t - 小寫字母t。匹配標(biāo)簽。
- re.search(r'Eat\tcake', 'Eat cake').group()
- 'Eat\tcake'
- \n - 小寫字母n。匹配換行符。
- \r - 小寫字母r。比賽歸來。
- \d - 小寫字母d。匹配十進(jìn)制數(shù)字0-9。
- re.search(r'c\d\dkie', 'c00kie').group()'c00kie'
- ^-插入符號 在字符串的開頭匹配一個模式。
- re.search(r'^Eat', 'Eat cake').group()'Eat'
- $ -匹配字符串末尾的模式。
- re.search(r'cake$', 'Eat cake').group()
- 'cake'
[abc] -匹配a或b或c。
[a-zA-Z0-9]-匹配(a至z)或(A至Z)或(0至9)中的任何字母??梢酝ㄟ^補(bǔ)充集合來匹配不在范圍內(nèi)的字符。如果集合的第一個字符是^,則所有不在集合中的字符都將被匹配。
- re.search(r'Number: [0-6]', 'Number: 5').group()
- 'Number: 5'
- # Matches any character except 5
- re.search(r'Number: [^5]', 'Number: 0').group()
- 'Number: 0'
- \A-大寫a。僅在字符串開頭匹配。也可以跨多行工作。
- re.search(r'\A[A-E]ookie', 'Cookie').group()
- 'Cookie'
- \b-小寫字母b。僅匹配單詞的開頭或結(jié)尾。
- re.search(r'\b[A-E]ookie', 'Cookie').group()
- 'Cookie'
- \-反斜杠。如果反斜杠后面的字符是公認(rèn)的轉(zhuǎn)義字符,則采用該術(shù)語的特殊含義。例如,\n被視為換行符。但是,如果后面的字符\不是可識別的轉(zhuǎn)義字符,則將\象任何其他字符一樣對待并通過。
讓我們看幾個例子:
- # This checks for '\' in the string instead of '\t' due to the '\' used
- re.search(r'Back\\stail', 'Back\stail').group()
- 'Back\\stail'
- # This treats '\s' as an escape character because it lacks '\' at the start of '\s'
- re.search(r'Back\stail', 'Back tail').group()
- 'Back lash'
- 重復(fù)次數(shù)
如果您要查找序列中的長模式,將變得非常乏味。幸運的是,該re模塊使用以下特殊字符處理重復(fù):
- + -檢查其左側(cè)的一個或多個字符。
- re.search(r'Co+kie', 'Cooookie').group()
- 'Cooookie'
- * -檢查左側(cè)是否有零個或多個字符。
- # Checks for any occurrence of a or o or both in the given sequence
- re.search(r'Ca*o*kie', 'Caokie').group()
- 'Caokie'
- ? -檢查其左邊是否為零或一個字符。
- # Checks for exactly zero or one occurrence of a or o or both in the given sequence
- re.search(r'Colou?r', 'Color').group()
- 'Color'
但是,如果您要檢查序列重復(fù)的確切數(shù)目怎么辦?
例如,檢查應(yīng)用程序中電話號碼的有效性。re模塊還使用以下正則表達(dá)式很好地處理了此問題:
{x} -重復(fù)x次。
{x,} -重復(fù)至少x次或更多。
{x, y} -重復(fù)至少x次,但不超過y次。
- re.search(r'\d{9,10}', '0987654321').group()
- '0987654321'
將+和*資格賽被認(rèn)為是greedy。
- 使用正則表達(dá)式進(jìn)行分組和分組
假設(shè),當(dāng)您驗證電子郵件地址并想要分別檢查用戶名和主機(jī)時。
這是group正則表達(dá)式功能派上用場的時候。它允許您拾取匹配文本的一部分。
由括號()界定的正則表達(dá)式模式的部分稱為groups。括號不會更改表達(dá)式匹配的內(nèi)容,而是在匹配的序列內(nèi)形成組。group()在本教程的示例中,您一直都在使用該功能。match.group()像平常一樣,沒有任何參數(shù)的純文本仍然是整個匹配文本。
- email_address = 'Please contact us at: support@datacamp.com'
- match = re.search(r'([\w\.-]+)@([\w\.-]+)', ____________)
- if _____:
- print(match.group()) # The whole matched text
- print(match.group(1)) # The username (group 1)
- print(match.group(2)) # The host (group 2)
貪婪vs非貪婪匹配
當(dāng)特殊字符與搜索序列(字符串)盡可能匹配時,則稱為"貪婪匹配"。這是正則表達(dá)式的正常行為,但有時不希望出現(xiàn)這種行為:
- pattern = "cookie"
- sequence = "Cake and cookie"
- heading = r'<h1>TITLE</h1>'
- re.match(r'<.*>', heading).group()
- '<h1>TITLE</h1>'
該模式<.*>匹配整個字符串,直到第二次出現(xiàn)為止>。
但是,如果只想匹配第一個
標(biāo)記,則可以使用貪婪的限定符*?,該限定符匹配的文字越少越好。
?在限定符之后添加使其以非貪婪或最小的方式執(zhí)行匹配;也就是說,將匹配盡可能少的字符。跑步時<.*>,您只會與比賽<h1>。
- heading = r'<h1>TITLE</h1>'
- re.match(r'<.*?>', heading).group()
- '<h1>'
re Python庫
Re Python中的庫提供了幾個函數(shù),使其值得掌握。您已經(jīng)看過其中的一些,例如re.search(),re.match()。讓我們詳細(xì)檢查一些有用的功能:
- search(pattern, string, flags=0)
使用此功能,您可以掃描給定的字符串/序列,以查找正則表達(dá)式產(chǎn)生匹配項的第一個位置。如果找到,則返回相應(yīng)的匹配對象;否則,None如果字符串中沒有位置與模式匹配,則返回。請注意,這None與在字符串中的某個點找到零長度匹配不同。
- pattern = "cookie"
- sequence = "Cake and cookie"
- re.search(pattern, sequence).group()
- 'cookie'
- match(pattern, string, flags=0)
如果字符串開頭的零個或多個字符與模式匹配,則返回相應(yīng)的匹配對象。否則None,如果字符串與給定的模式不匹配,則返回。
- pattern = "C"
- sequence1 = "IceCream"
- # No match since "C" is not at the start of "IceCream"
- re.match(pattern, sequence1)
- sequence2 = "Cake"
- re.match(pattern,sequence2).group()
- 'C'
search() 與 match()
該match()函數(shù)僅在字符串的開頭檢查匹配項(默認(rèn)情況下),而該search()函數(shù)在字符串的任何位置檢查匹配項。
- findall(pattern, string, flags=0)
查找整個序列中所有可能的匹配項,并將它們作為字符串列表返回。每個返回的字符串代表一個匹配項。
- email_address = "Please contact us at: support@datacamp.com, xyz@datacamp.com"
- #'addresses' is a list that stores all the possible match
- addresses = re.findall(r'[\w\.-]+@[\w\.-]+', email_address)for address in addresses:
- print(address)
- support@datacamp.com
- xyz@datacamp.com
- sub(pattern, repl, string, count=0, flags=0)
這就是substitute功能。它返回通過用替換替換或替換字符串中最左邊的非重疊模式所獲得的字符串repl。如果找不到該模式,則該字符串將原樣返回。
- email_address = "Please contact us at: xyz@datacamp.com"
- new_email_address = re.sub(r'([\w\.-]+)@([\w\.-]+)', r'support@datacamp.com', email_address)
- print(new_email_address)
- Please contact us at: support@datacamp.com
- compile(pattern, flags=0)
將正則表達(dá)式模式編譯為正則表達(dá)式對象。當(dāng)您需要在單個程序中多次使用表達(dá)式時,使用該compile()函數(shù)保存生成的正則表達(dá)式對象以供重用會更有效。這是因為compile()緩存了傳遞給的最新模式的編譯版本以及模塊級匹配功能。
- pattern = re.compile(r"cookie")
- sequence = "Cake and cookie"
- pattern.search(sequence).group()
- 'cookie'
- # This is equivalent to:
- re.search(pattern, sequence).group()
- 'cookie'
提示:可以通過指定flags值來修改表達(dá)式的行為。您可以flag在本教程中看到的各種功能中添加一個額外的參數(shù)。一些使用的標(biāo)志是:IGNORECASE,DOTALL,MULTILINE,VERBOSE,等。
案例研究:使用正則表達(dá)式
通過學(xué)習(xí)一些示例,您已經(jīng)了解了正則表達(dá)式在Python中的工作方式,是時候動手了!在本案例研究中,您將運用自己的知識。
- import reimport requests
- the_idiot_url = 'https://www.gutenberg.org/files/2638/2638-0.txt'
- def get_book(url):
- # Sends a http request to get the text from project Gutenberg
- raw = requests.get(url).text
- # Discards the metadata from the beginning of the book
- start = re.search(r"\*\*\* START OF THIS PROJECT GUTENBERG EBOOK .*\*\*\*",raw ).end()
- # Discards the metadata from the end of the book
- stop = re.search(r"II", raw).start()
- # Keeps the relevant text
- text = raw[start:stop]
- return text
- def preprocess(sentence):
- return re.sub('[^A-Za-z0-9.]+' , ' ', sentence).lower()
- book = get_book(the_idiot_url)
- processed_book = preprocess(book)
- print(processed_book)
在語料庫中找到代詞" the"的編號。提示:使用len()功能。
- len(re.findall(r'the', processed_book))
- 302
嘗試將語料庫中的每個" i"的獨立實例轉(zhuǎn)換為" I"。確保不要更改一個單詞中出現(xiàn)的" i":
- processed_book = re.sub(r'\si\s', " I ", processed_book)
- print(processed_book)
查找""語料庫中有人被引號()的次數(shù)。
- len(re.findall(r'\"', book))
- 96
什么是由連接的話'--'在語料庫?
- re.findall(r'[a-zA-Z0-9]*--[a-zA-Z0-9]*', book)
- ['ironical--it',
- 'malicious--smile',
- 'fur--or',
- ------------省略
- ]
結(jié)束
恭喜你!您已經(jīng)完成了Python正則表達(dá)式的教程!使用Python,您的數(shù)據(jù)科學(xué)之旅將涉及更多內(nèi)容。
正則表達(dá)式可以在數(shù)據(jù)預(yù)處理階段發(fā)揮重要作用。