Python利用re模塊實(shí)現(xiàn)簡易分詞(tokenization)
一個簡單的tokenizer
分詞(tokenization)任務(wù)是Python字符串處理中最為常見任務(wù)了。我們這里講解用正則表達(dá)式構(gòu)建簡單的表達(dá)式分詞器(tokenizer),它能夠?qū)⒈磉_(dá)式字符串從左到右解析為標(biāo)記(tokens)流。
給定如下的表達(dá)式字符串:
text = 'foo = 12 + 5 * 6'
我們想要將其轉(zhuǎn)換為下列以序列對呈現(xiàn)的分詞結(jié)果:
tokens = [('NAME', 'foo'), ('EQ', '='), ('NUM', '12'), ('PLUS', '+'),\
('NUM', '5'), ('TIMES', '*'), ('NUM', '6')]
要完成這樣的分詞操作,我們首先需要定義出所有可能的標(biāo)記模式(所謂模式(pattern),為用來描述或者匹配/系列匹配某個句法規(guī)則的字符串,這里我們用正則表達(dá)式來做為模式),注意此處要包括空格whitespace,否則字符串中出現(xiàn)任何模式中沒有的字符后,掃描就會停止。因?yàn)槲覀冞€需要給標(biāo)記以NAME、EQ等名稱,我們采用正則表達(dá)式中的命名捕獲組來實(shí)現(xiàn)。
import re
NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
# 這里?P<NAME>表示模式名稱,()表示一個正則表達(dá)式捕獲組,合在一起即一個命名捕獲組
EQ = r'(?P<EQ>=)'
NUM = r'(?P<NUM>\d+)' #\d表示匹配數(shù)字,+表示任意數(shù)量
PLUS = r'(?P<PLUS>\+)' #需要用\轉(zhuǎn)義
TIMES = r'(?P<TIMES>\*)' #需要用\轉(zhuǎn)義
WS = r'(?P<WS>\s+)' #\s表示匹配空格, +表示任意數(shù)量
master_pat = re.compile("|".join([NAME, EQ, NUM, PLUS, TIMES, WS])) # | 用于選擇多個模式,表示"或"
接下來我們用模式對象中的scanner()方法來完成分詞操作,該方法創(chuàng)建一個掃描對象:
scanner = master_pat.scanner(text)
然后可以用match()方法獲取單次匹配結(jié)果,一次匹配一個模式:
scanner = master_pat.scanner(text) m = scanner.match() print(m.lastgroup, m.group()) # NAME foo m = scanner.match() print(m.lastgroup, m.group()) # WS
當(dāng)然這樣一次一次調(diào)用過于麻煩,我們可以使用迭代器來批量調(diào)用,并將單次迭代結(jié)果以具名元組形式存儲
Token = namedtuple('Token', ['type', 'value'])
def generate_tokens(pat, text):
scanner = pat.scanner(text)
for m in iter(scanner.match, None):
#scanner.match做為迭代器每次調(diào)用的方法,
#None為哨兵的默認(rèn)值,表示迭代到None停止
yield Token(m.lastgroup, m.group())
for tok in generate_tokens(master_pat, "foo = 42"):
print(tok)
最終顯示表達(dá)式串"foo = 12 + 5 * 6"的tokens流為:
Token(type='NAME', value='foo') Token(type='WS', value=' ') Token(type='EQ', value='=') Token(type='WS', value=' ') Token(type='NUM', value='12') Token(type='WS', value=' ') Token(type='PLUS', value='+') Token(type='WS', value=' ') Token(type='NUM', value='5') Token(type='WS', value=' ') Token(type='TIMES', value='*') Token(type='WS', value=' ') Token(type='NUM', value='6')
過濾tokens流
接下來我們想要過濾掉空格標(biāo)記,使用生成器表達(dá)式即可:
tokens = (tok for tok in generate_tokens(master_pat, "foo = 12 + 5 * 6")
if tok.type != 'WS')
for tok in tokens:
print(tok)
可以看到空格被成功過濾:
Token(type='NAME', value='foo') Token(type='EQ', value='=') Token(type='NUM', value='12') Token(type='PLUS', value='+') Token(type='NUM', value='5') Token(type='TIMES', value='*') Token(type='NUM', value='6')
注意子串匹配陷阱
tokens在正則表達(dá)式(即"|".join([NAME, EQ, NUM, PLUS, TIMES, WS]))中順序也非常重要。因?yàn)樵谶M(jìn)行匹配時,re模塊就會按照指定的順序?qū)δJ阶銎ヅ洹9嗜襞銮赡硞€模式是另一個較長模式的子串時,必須保證較長的模式在前面優(yōu)先匹配。如下面分別展示正確的和錯誤的匹配方法:
LT = r'(?P<LT><)'
LE = r'(?P<LE><=)'
EQ = r'(?P<EQ>>=)'
master_pat = re.compile("|".join([LE, LT, EQ])) # 正確的順序
master_pat = re.compile("|".join([LT, LE, EQ])) # 錯誤的順序
第二種順序的錯誤之處在于,這樣會把'<='文本匹配為LT('<')緊跟著EQ('='),而沒有匹配為單獨(dú)的LE(<=)。
我們對于“有可能”形成子串的模式也要小心,比如下面這樣:
PRINT = r'(?P<PRINT>print)'
NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)'
master_pat = re.compile("|".join([PRINT, NAME])) # 正確的順序
for tok in generate_tokens(master_pat, "printer"):
print(tok)
可以看到被print實(shí)際上成了另一個模式的子串,導(dǎo)致另一個模式的匹配出現(xiàn)了問題:
# Token(type='PRINT', value='print') # Token(type='NAME', value='er')
更高級的語法分詞,建議采用像PyParsing或PLY這樣的包。特別地,對于英文自然語言文章的分詞,一般被集成到各類NLP的包中(一般分為按空格拆分、處理前后綴、去掉停用詞三步驟)。對于中文自然語言處理分詞也有豐富的工具(比如jieba分詞工具包)。
到此這篇關(guān)于Python利用re模塊實(shí)現(xiàn)簡易分詞(tokenization)的文章就介紹到這了,更多相關(guān)Python 分詞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python的numpy庫中將矩陣轉(zhuǎn)換為列表等函數(shù)的方法
下面小編就為大家分享一篇Python的numpy庫中將矩陣轉(zhuǎn)換為列表等函數(shù)的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04
解決TensorFlow訓(xùn)練內(nèi)存不斷增長,進(jìn)程被殺死問題
今天小編就為大家分享一篇解決TensorFlow訓(xùn)練內(nèi)存不斷增長,進(jìn)程被殺死問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
PyQt5實(shí)現(xiàn)用戶登錄GUI界面及登錄后跳轉(zhuǎn)
PyQt5是強(qiáng)大的GUI工具之一,通過其可以實(shí)現(xiàn)優(yōu)秀的桌面應(yīng)用程序。本文主要介紹了PyQt5實(shí)現(xiàn)用戶登錄GUI界面及登錄后跳轉(zhuǎn),具有一定的參考價值,感興趣的可以了解一下2021-11-11
Python實(shí)現(xiàn)的簡單排列組合算法示例
這篇文章主要介紹了Python實(shí)現(xiàn)的簡單排列組合算法,涉及Python使用itertools庫進(jìn)行排列組合運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)通過公共鍵對字典列表排序算法示例
這篇文章主要介紹了Python cookbook(數(shù)據(jù)結(jié)構(gòu)與算法)通過公共鍵對字典列表排序算法,結(jié)合實(shí)例形式分析了Python基于operator模塊中的itemgetter()函數(shù)對字典進(jìn)行排序的相關(guān)操作技巧,需要的朋友可以參考下2018-03-03

