您好,登錄后才能下訂單哦!
這篇文章主要介紹“Python中如何使用re模塊實現okenizer”,在日常操作中,相信很多人在Python中如何使用re模塊實現okenizer問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Python中如何使用re模塊實現okenizer”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
分詞(tokenization)任務是Python字符串處理中最為常見任務了。我們這里講解用正則表達式構建簡單的表達式分詞器(tokenizer),它能夠將表達式字符串從左到右解析為標記(tokens)流。
給定如下的表達式字符串:
text = 'foo = 12 + 5 * 6'
我們想要將其轉換為下列以序列對呈現的分詞結果:
tokens = [('NAME', 'foo'), ('EQ', '='), ('NUM', '12'), ('PLUS', '+'),\ ('NUM', '5'), ('TIMES', '*'), ('NUM', '6')]
要完成這樣的分詞操作,我們首先需要定義出所有可能的標記模式(所謂模式(pattern),為用來描述或者匹配/系列匹配某個句法規則的字符串,這里我們用正則表達式來做為模式),注意此處要包括空格whitespace,否則字符串中出現任何模式中沒有的字符后,掃描就會停止。因為我們還需要給標記以NAME、EQ等名稱,我們采用正則表達式中的命名捕獲組來實現。
import re NAME = r'(?P<NAME>[a-zA-Z_][a-zA-Z_0-9]*)' # 這里?P<NAME>表示模式名稱,()表示一個正則表達式捕獲組,合在一起即一個命名捕獲組 EQ = r'(?P<EQ>=)' NUM = r'(?P<NUM>\d+)' #\d表示匹配數字,+表示任意數量 PLUS = r'(?P<PLUS>\+)' #需要用\轉義 TIMES = r'(?P<TIMES>\*)' #需要用\轉義 WS = r'(?P<WS>\s+)' #\s表示匹配空格, +表示任意數量 master_pat = re.compile("|".join([NAME, EQ, NUM, PLUS, TIMES, WS])) # | 用于選擇多個模式,表示"或"
接下來我們用模式對象中的scanner()
方法來完成分詞操作,該方法創建一個掃描對象:
scanner = master_pat.scanner(text)
然后可以用match()
方法獲取單次匹配結果,一次匹配一個模式:
scanner = master_pat.scanner(text) m = scanner.match() print(m.lastgroup, m.group()) # NAME foo m = scanner.match() print(m.lastgroup, m.group()) # WS
當然這樣一次一次調用過于麻煩,我們可以使用迭代器來批量調用,并將單次迭代結果以具名元組形式存儲
Token = namedtuple('Token', ['type', 'value']) def generate_tokens(pat, text): scanner = pat.scanner(text) for m in iter(scanner.match, None): #scanner.match做為迭代器每次調用的方法, #None為哨兵的默認值,表示迭代到None停止 yield Token(m.lastgroup, m.group()) for tok in generate_tokens(master_pat, "foo = 42"): print(tok)
最終顯示表達式串"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 = (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在正則表達式(即"|".join([NAME, EQ, NUM, PLUS, TIMES, WS])
)中順序也非常重要。因為在進行匹配時,re
模塊就會按照指定的順序對模式做匹配。故若碰巧某個模式是另一個較長模式的子串時,必須保證較長的模式在前面優先匹配。如下面分別展示正確的和錯誤的匹配方法:
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('='
),而沒有匹配為單獨的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
實際上成了另一個模式的子串,導致另一個模式的匹配出現了問題:
# Token(type='PRINT', value='print') # Token(type='NAME', value='er')
更高級的語法分詞,建議采用像PyParsing或PLY這樣的包。特別地,對于英文自然語言文章的分詞,一般被集成到各類NLP的包中(一般分為按空格拆分、處理前后綴、去掉停用詞三步驟)。對于中文自然語言處理分詞也有豐富的工具(比如jieba
分詞工具包)。
[1] Martelli A, Ravenscroft A, Ascher D. Python cookbook[M]. " O'Reilly Media, Inc.", 2015. 數學是符號的藝術,音樂是上界的語言。
到此,關于“Python中如何使用re模塊實現okenizer”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。