如何用 Python 和正則表達式抽取文本結構化信息缩麸?

簡單铸磅、直接、高效地從文本中提煉關鍵內容杭朱。讓你體驗正則表達式的威力愚屁。

痛點

很多人的日常工作,都是要和大量的文本打交道的痕檬。

例如學者需要閱讀大量的文獻材料霎槐,從中找到靈感、數(shù)據(jù)與論據(jù)梦谜。

學生需要閱讀很多教科書和論文丘跌,然后寫自己的報告或者做幻燈。

財經(jīng)分析師唁桩,需要從大量的新聞報道中闭树,找到行業(yè)的發(fā)展趨勢和目標企業(yè)動態(tài)的蛛絲馬跡。

不是所有的文本處理荒澡,都那么新鮮而有趣报辱。

有一項重要但繁瑣的工作,就是從大量的文本當中抽取結構化的信息单山。

許多數(shù)據(jù)分析的場景碍现,都要求輸入結構化的信息。

例如在咱們之前介紹過的《貸還是不貸:如何用Python和機器學習幫你決策米奸?》和《如何用Python和深度神經(jīng)網(wǎng)絡鎖定即將流失的客戶昼接?》中,你都看到了悴晰,機器模型更喜歡被結構化的表格信息來喂養(yǎng)慢睡。

然而,結構化的信息铡溪,不一定就在那里漂辐,靜候你來使用。很多時候棕硫,它蘊藏在以往生成的非結構化文本中髓涯。

你可能早已習慣,人工閱讀文本信息饲帅,把關鍵點摘取出來复凳,然后把它們拷貝粘貼放到一個表格中瘤泪。從原理上講灶泵,這樣做無可厚非育八。但是實際操作里面,效率太低赦邻,而且太麻煩髓棋。

大部分人,是不愿意從事這種簡單重復的枯燥工作的惶洲。

一遍遍機械重復鼠標劃定文本范圍按声,“Ctrl+C”、切換到表格文檔恬吕、找準輸入位置签则,再“Ctrl+V”……

這種事兒做得太多,對你的肩肘關節(jié)铐料,甚至是身心健康渐裂,都有可能造成不利影響。

想不想嘗試用一種更簡單的自動化方式钠惩,替你快速完成這些煩人的操作步驟呢柒凉?

讀過本文后,希望你能找到答案篓跛。

樣例

這里膝捞,我們舉一個極端簡化的中文文本抽取信息例子。

之所以這樣做愧沟,是為了避免你在解讀數(shù)據(jù)上花費太多時間蔬咬。

我更希望,你能夠聚焦于方法沐寺,從而掌握新知计盒。

假設一個高中班主任,高考后讓班長統(tǒng)計一下學生們的畢業(yè)去向芽丹。班長很認真地進行了調查北启,然后做了如下匯報:

張華考上了北京大學
李萍進了中等技術學校
韓梅梅進了百貨公司
……

為了讓你對樣例足夠熟悉,甚至有共鳴拔第,這里我從1998年版的新華字典中咕村,“借鑒”了部分內容。

夠貼心吧蚊俺?

現(xiàn)實生活中懈涛,一個班大概不會只有3個人,因此你可以想象這是一個長長的句子列表泳猬。

但其實班主任有個隱含的意思沒有表達出來批钠,即:

我想要一張表格宇植!

所以,看到這一長串的句子埋心,你可以想象他的表情指郁。

班長估計也很難堪:

想要表格你早說啊拷呆!

這時候闲坎,假設你是班長,怎么辦茬斧?

信息都在文本里面腰懂。但如果需要轉換成表格,就得一個個信息點去尋找和處理项秉。

其實绣溜,對于四五十人的班級來說,手動操作也不是什么太難的事情娄蔼。

但是設想一下怖喻,如果你需要處理的數(shù)據(jù)量,是這個例子的十倍贷屎、百倍甚至千萬倍呢罢防?

繼續(xù)堅持手動處理?

這不僅麻煩唉侄,而且不現(xiàn)實咒吐。

我們需要找到一種簡單的方法,幫助我們自動抽取相應的信息属划。

此處我們使用的方法恬叹,是正則表達式

正則

“正則表達式”這個名字同眯,初聽起來好像很玄妙绽昼。實際上,它是從英文“regular expression”翻譯過來的须蜗。

如果譯成白話硅确,那就是“有規(guī)律的表述形式”。

這明肮,聽起來菱农,是不是就更加接地氣了?

但是柿估,給你補一下“假行家101”課程:

說別人聽得懂的話循未,你能唬得住誰?

約定俗成秫舌,咱們繼續(xù)沿用“正則表達式”的妖,來稱呼它好了绣檬。

從創(chuàng)生之日起,它就給文本處理帶來了高效率嫂粟。

但是娇未,用它的主要人群,卻不是時常跟文字打交道的作家赋元、編輯忘蟹、學者飒房、文員搁凸,而是……

程序員!

程序員寫的代碼狠毯,是文本护糖;程序員處理的數(shù)據(jù),很多也是文本格式嚼松。其中便有很多顯著的規(guī)律可循嫡良。

正是靠著正則表達式這種獨門秘籍,許多別人做起來献酗,需要昏天黑地一整周的任務寝受,程序員可以半小時搞定,然后喝著咖啡等下班罕偎。

即便到了泛人工智能的今天很澄,正則表達式依然有許多令你意想不到的應用。

例如人機對話系統(tǒng)颜及。

你可能看了新聞報道甩苛,總以為人機對話都是靠著知識圖譜或者深度學習搞出來的。

不能說這里面俏站,沒有上述炫酷技術的參與讯蒲。但它們充其量,只占其中一部分肄扎,或許還只是一小部分墨林。

生產實踐里面,大量的對話規(guī)則后面犯祠,并不是讓你倍感神奇深奧的神經(jīng)網(wǎng)絡旭等,而是一堆正則表達式。

你可能會擔心雷则,這樣高端的應用技術辆雾,自己能掌握嗎?

答案是:

當然月劈!

正則表達式度迂,并不難學藤乙。

尤其是當你把它和 Python 結合到一起,那簡直就是效率神器了惭墓。

我們這就來看看坛梁,正則表達式怎么幫我們識別出樣例文本里面“人名”和“去向”信息。

試練

請你開啟一個瀏覽器腊凶,鍵入這個網(wǎng)址(https://regex101.com/)划咐。

你會看見如下界面。

它可是一個正則表達式實驗的利器钧萍。我教 INFO 5731 課程時褐缠,學生們就是在掌握了這個工具以后,迅速玩兒轉了正則表達式风瘦。

這么好的工具队魏,一定要價不菲吧?

不万搔,它是免費的胡桨。你放心大膽使用就好了。

我們首先把左側的編程語言瞬雹,從默認的 PHP 昧谊,調整為 Python。

之后酗捌,把需要進行處理的文本呢诬,貼到中間空白的大文本框里面。

下面我們來嘗試進行“匹配”意敛。

什么叫做匹配呢馅巷?

就是你寫一個表達式,電腦便拿著雞毛當令箭草姻,在每一行文本上钓猬,都認認真真地找有沒有符合該表達式的文本段落。

如有撩独,則會高亮顯示出來敞曹。

這里我們觀察一下,發(fā)現(xiàn)每個句子里面综膀,人員去向前面澳迫,都有一個“了”字。

好剧劝,我們就在中部上方小文本框里橄登,把“了”字輸入進去。

可以看到,三句話里面的“了”拢锹,全都亮了谣妻。

這就是你接觸到的第一種匹配方式——按照字符原本的意思來查找一致的內容。

因為樣例文本的規(guī)律性卒稳,我們可以把“了”當成一個定位符蹋半,它后面,到句子結束位置充坑,是“去向”信息减江。

咱們需要找的一半結構化信息,不就是這個“去向”嗎捻爷?

我們嘗試匹配“去向”辈灼。

怎么匹配呢?這次每一行的字兒都不一樣耙酆狻茵休?

沒關系薪棒,正則表達式強大之處手蝎,此時就顯示出來了。

你可以用一個點號俐芯,也就是.棵介,表示任意字符。

字母吧史、數(shù)字邮辽、標點……甚至是中文,也能涵蓋在內贸营。

然后我們繼續(xù)想想看吨述,去向信息這里,會有幾個字呢钞脂?

不好說揣云。

例子里面這簡單的三句話,就有“4個字”或者“6個字”兩種情況冰啃。

所以邓夕,我們無法指定去向信息里面字符的長度。

但這也沒關系阎毅,我們只需要用一個星號(*)焚刚,就可以代表出現(xiàn)次數(shù),從0到無窮大都可以匹配扇调。

當然矿咕,實際情況中,是不會真出現(xiàn)無窮大的。

我們在剛才輸入的基礎上碳柱,加上.*雌团,結果就成了這個樣子:

不錯嘛!

不過似乎去向信息和“了”字兒都是一樣顏色的高亮士聪。那不就混到了一起嗎锦援?

我們可不想這樣。

怎么辦剥悟?

請你在.*的兩側灵寺,嘗試加入一對小括號(注意,不要用中文全角符號)試試看区岗。

你會發(fā)現(xiàn)略板,這次“了”依然用藍色表示,而后面的去向信息慈缔,已經(jīng)變成了綠色叮称。

這一對小括號,很重要藐鹤,它叫做“分組”瓤檐,是提取信息的基本單位。

我們的任務已經(jīng)解決了一半了,是吧?

下面我們來嘗試把人名一并抽取出來咆贬。

我們來找人名的錨定位置。

細細觀察谴古,你不難發(fā)現(xiàn),每個人名的后面稠歉,都有個動詞跟著掰担。

升學的同學,用的是“考”字怒炸,而就業(yè)的同學带饱,用的是“進”字。

我們先嘗試一下“考”字横媚。

這里我們嘗試直接把“考”字放在“了”字以前纠炮。但是你會發(fā)現(xiàn),什么匹配結果也沒有灯蝴。

為什么恢口?

回看數(shù)據(jù),你會發(fā)現(xiàn)穷躁,人家用的原詞是“考上了”耕肩。

當然這里我們可以輸入“上”字因妇。不過你要考慮一下更為通用的情況。

好比說猿诸,“考取了”怎么辦婚被?“考入了”呢?

更好的方式梳虽,是繼續(xù)使用我們剛才學會的“大招”址芯,在“考”和“了”之間,插入一個.*窜觉。

這時候谷炸,你的正則表達式的樣子是 考.*了(.*)

看,第一行的信息成功匹配了吧禀挫?

但是旬陡,那后面還有兩行沒有匹配,怎么辦语婴?

我們依樣畫葫蘆描孟,就會發(fā)現(xiàn),使用進.*了(.*)就能正確匹配后兩行砰左。

問題來了:

匹配第一行的匿醒,匹配不了后兩行,反之亦然菜职。

這不好青抛。我們希望寫的表達式,能夠更通用酬核。

怎么辦?

我們看看正則表達式當中“或”關系的表示适室。

這里嫡意,我們可以把兩個字符用豎線隔開,旁邊用中括號括起來捣辆,代表兩者任一出現(xiàn)蔬螟,都算匹配成功。

也就是汽畴,把正則表達式旧巾,寫成這樣:[考|進].*了(.*)

太棒了,三行的內容都已經(jīng)匹配成功忍些。

這里鲁猩,動詞詞組,和代表時態(tài)的“了”作為中間錨定信息罢坝,我們可以放心大膽廓握,把之前的人名信息,提取出來了。

也就是這樣寫:(.*)[考|進].*了(.*)

注意此時隙券,人名分組是綠色男应,去向分組是紅色的。

我們成功提取了兩組信息娱仔!慶祝一下沐飘!

可是,如果你給班主任看這里的結果牲迫,估計他不會滿意薪铜。

表格,我要表格恩溅!

別著急隔箍,該 Python 出場了。

下面我們嘗試在 Python 把數(shù)據(jù)正式提取出來脚乡。

環(huán)境

本文的配套源代碼蜒滩,我放在了 Github 上。

你可以在我的公眾號“玉樹芝蘭”(nkwangshuyi)后臺回復“regex”奶稠,查看完整的代碼鏈接俯艰。

如果你對我的教程滿意,歡迎在頁面右上方的 Star 上點擊一下锌订,幫我加一顆星竹握。謝謝!

注意這個頁面的中央辆飘,有個按鈕啦辐,寫著“在 Colab 打開”(Open in Colab)。請你點擊它蜈项。

然后芹关,Google Colab 就會自動開啟。

我建議你點一下上圖中紅色圈出的 “COPY TO DRIVE” 按鈕紧卒。這樣就可以先把它在你自己的 Google Drive 中存好侥衬,以便使用和回顧。

Colab 為你提供了全套的運行環(huán)境跑芳。你只需要依次執(zhí)行代碼轴总,就可以復現(xiàn)本教程的運行結果了。

如果你對 Google Colab 不熟悉博个,沒關系怀樟。我這里有一篇教程,專門講解 Google Colab 的特點與使用方式坡倔。

為了你能夠更為深入地學習與了解代碼漂佩,我建議你在 Google Colab 中開啟一個全新的 Notebook 脖含,并且根據(jù)下文,依次輸入代碼并運行投蝉。在此過程中养葵,充分理解代碼的含義。

這種看似笨拙的方式瘩缆,其實是學習的有效路徑关拒。

代碼

首先,讀入 Python 正則表達式包庸娱。

import re

然后着绊,我們把數(shù)據(jù)準備好。注意為了演示代碼的通用性熟尉,我這里在最后加了一行文字归露,區(qū)別于之前的文字規(guī)律,看看我們的代碼能否正確處理它斤儿。

data = """張華考上了北京大學
李萍進了中等技術學校
韓梅梅進了百貨公司
他們都有光明的前途"""

然后剧包,該寫正則表達式了。你真的需要自己手動來寫嗎往果?

當然不必疆液。

強大的 regex101 網(wǎng)站,已經(jīng)幫助我們準備好了陕贮。

請你點擊上圖中紅色圈出的按鈕堕油,網(wǎng)站會為你準備好一個初始代碼的模板,可以匹配你需要的模式肮之。

你不需要完全照搬代碼掉缺。其中有這樣一句,是很重要的局骤,拷貝過來攀圈,貼到 Colab Notebook 就好。

regex = r"(.*)[考|進].*了(.*)"

以上就是你的正則表達式峦甩,在 Python 里面應有的樣子。

我們準備一個空列表现喳,用來接收數(shù)據(jù)凯傲。

mylist = []

接著,寫一個循環(huán)嗦篱。

for line in data.split('\n'):
  mysearch = re.search(regex, line)
  if mysearch:
    name = mysearch.group(1)
    dest = mysearch.group(2)
    mylist.append((name, dest))

我給你解釋一下這個循環(huán)里面冰单,各條語句的含義:

  • data.split('\n') 把文本數(shù)據(jù)按行來拆分開。這樣我們就可以針對每一行灸促,來獲取數(shù)據(jù)诫欠。
  • mysearch = re.search(regex, line) 這一句嘗試匹配模式到該行內容涵卵。
  • if mysearch 這個判斷語句,是讓程序分辨一下荒叼,該行是否有我們要找的模式轿偎。例如最后一行文字,里面并沒有咱們前面分析的文字模式被廓。遇到這樣的行坏晦,直接跳過。
  • name = mysearch.group(1) 是說匹配的第一組內容嫁乘,也就是 regex101 網(wǎng)站里綠色代表的人名分組存到 name 變量里昆婿。下一句依次類推。注意 group 對應你正則表達式里面小括號出現(xiàn)的順序蜓斧,從1開始計數(shù)仓蛆。
  • mylist.append((name, dest)) 把該行抽取到的信息,存入到咱們之前定義的空列表里面挎春。

注意看疙,如果不加 mysearch = re.search(regex, line) 這一句,程序會對每一行都嘗試匹配并且抽取分組內容搂蜓,那么結果就會報這樣的錯誤:

所以你看狼荞,用正則表達式抽取信息時,不能蠻干帮碰。

此時相味,我們查看一下 mylist 這個列表里面的內容:

mylist

結果為:

[('張華', '北京大學'), ('李萍', '中等技術學校'), ('韓梅梅', '百貨公司')]

不錯,一個不多殉挽,一個不少丰涉,恰好是我們需要的。

我們要把它導出成為表格斯碌。方法有很多一死,但是最簡便順手的,是用 Pandas 數(shù)據(jù)分析軟件包傻唾。

import pandas as pd

只需要利用 pd.DataFrame 函數(shù)投慈,我們就能把上面列表和元組(tuple)組成的一個二維結構,變成數(shù)據(jù)框冠骄。

df = pd.DataFrame(mylist)
df.columns = ['姓名', '去向']

注意伪煤,這里我們還非常細心地修改了表頭。

看看你的勞動成果吧:

df

有了數(shù)據(jù)框凛辣,轉換成為 Excel 抱既,就是一行代碼的事情了:

df.to_excel("dest.xlsx", index=False)

進入 Files 標簽頁,刷新并且查看一下當前目錄下的內容:

這個 dest.xlsx 就是輸出的結果了扁誓。下載之后我們可以用 Excel 打開查看防泵。

任務完成蚀之!

你可以把結果提交給班主任,看他滿意的笑容了捷泞。

小結

這篇教程里面足删,咱們談了如何利用文本字符規(guī)律,借助 Python 和正則表達式肚邢,來提取結構化信息壹堰。

希望你已經(jīng)掌握了以下本領:

  • 了解正則表達式的功用;
  • 用 regex101 網(wǎng)站嘗試正則表達式匹配骡湖,并且生成初步的代碼贱纠;
  • 用 Python 批量提取信息,并且根據(jù)需求導出結構化數(shù)據(jù)為指定格式响蕴。

再次強調一下谆焊,對于這么簡單的樣例,使用上述方法浦夷,絕對是大炮轟蚊子辖试。

然而,如果你需要處理的數(shù)據(jù)是海量的劈狐,這個方法給你節(jié)省下來的時間罐孝,會非常可觀肥缔。

希望你能夠舉一反三莲兢,在自己的工作中靈活運用它。

資源

先別急著走续膳。

由于篇幅所限改艇,教程中我只給你介紹了幾項最簡單正則語法》夭恚肯定會有很多你感興趣的語法知識谒兄,沒來得及一一講給你聽。

如果你對于正則表達式很感興趣社付,因為科研或者工作目的承疲,需要馬上學習,也請不要著急鸥咖。

我這里剛好有一份免費的優(yōu)秀教程資源分享給你纪隙。

我在 UNT 講授 INFO 5731 課程的時候,就是用這份教程結合翻轉教學扛或,讓從沒聽說過正則表達式的學生們,在一兩周之內掌握并且熟練應用碘饼。相信對你來說熙兔,這份教程資源也會很有用悲伶。

你可以在我的公眾號“玉樹芝蘭”(nkwangshuyi)后臺回復“regex”,查看教程鏈接住涉。

祝學習愉快麸锉!

喜歡別忘了點贊

還可以微信關注我的公眾號“玉樹芝蘭”(nkwangshuyi)舆声。別忘了加星標花沉,以免錯過新推送提示。

如果本文可能對你身邊的親友有幫助媳握,也歡迎你把本文通過微博或朋友圈分享給他們碱屁。讓他們一起參與到我們的討論中來。

延伸閱讀

你可能也會對以下話題感興趣蛾找。點擊鏈接就可以查看娩脾。

題圖: Photo by Tim St. Martin on Unsplash

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市幻枉,隨后出現(xiàn)的幾起案子碰声,更是在濱河造成了極大的恐慌,老刑警劉巖熬甫,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胰挑,死亡現(xiàn)場離奇詭異,居然都是意外死亡罗珍,警方通過查閱死者的電腦和手機洽腺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來覆旱,“玉大人蘸朋,你說我怎么就攤上這事】鄢” “怎么了藕坯?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長噪沙。 經(jīng)常有香客問我炼彪,道長,這世上最難降的妖魔是什么正歼? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任辐马,我火速辦了婚禮,結果婚禮上局义,老公的妹妹穿的比我還像新娘喜爷。我一直安慰自己冗疮,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布檩帐。 她就那樣靜靜地躺著术幔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪湃密。 梳的紋絲不亂的頭發(fā)上诅挑,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機與錄音泛源,去河邊找鬼拔妥。 笑死,一個胖子當著我的面吹牛俩由,可吹牛的內容都是我干的毒嫡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼幻梯,長吁一口氣:“原來是場噩夢啊……” “哼兜畸!你這毒婦竟也來了?” 一聲冷哼從身側響起碘梢,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤咬摇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后煞躬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肛鹏,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年恩沛,在試婚紗的時候發(fā)現(xiàn)自己被綠了在扰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡雷客,死狀恐怖芒珠,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情搅裙,我是刑警寧澤皱卓,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站部逮,受9級特大地震影響娜汁,放射性物質發(fā)生泄漏。R本人自食惡果不足惜兄朋,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一掐禁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦穆桂、人聲如沸宫盔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至有额,卻和暖如春般又,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巍佑。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工茴迁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人萤衰。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓堕义,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脆栋。 傳聞我的和親對象是個殘疾皇子倦卖,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345