正群調整Python 編寫速度
Spark 是一種用 Python 編寫的強大的、通用的解析器/編譯器框架。在某些方面,Spark 所提供的比 SimpleParse 或其它 Python 解析器提供的都要多,下面進行學習研究。
然而,因為它完全是用 Python 編寫的,所以速度也會比較慢。David 在本文中討論了 Spark 模塊,給出了一些代碼樣本,解釋了它的用途,并對其應用領域提供了一些建議。本文中會介紹一些解析的基本概念,并對 Spark 模塊進行了討論。解析框架是一個內容豐富的主題,它值得我們多花時間去全面了解;
這兩篇文章為讀者和我自己都開了一個好頭。在日常的編程中,我經常需要標識存在于文本文檔中的部件和結構,這些文檔包括:日志文件、配置文件、定界的數據以及格式更自由的(但還是半結構化的)報表格式。所有這些文檔都擁有它們自己的“小語言”,用于規定什么能夠出現在文檔內。我編寫這些非正式解析任務的程序的方法總是有點象大雜燴。
其中包括定制狀態機、正則表達式以及上下文驅動的字符串測試。這些程序中的模式大概總是這樣:“讀一些文本,弄清是否可以用它來做些什么,然后可能再多讀一些文本,一直嘗試下去。”
解析器將文檔中部件和結構的描述提煉成簡明、清晰和說明性的規則,確定由什么組成文檔。大多數正式的解析器都使用擴展巴科斯范式(Extended Backus-Naur Form,EBNF)上的變體來描述它們所描述的語言的“語法”。
基本上,EBNF 語法對您可能在文檔中找到的部件賦予名稱;另外,較大的部件通常由較小的部件組成。小部件在較大的部件中出現的頻率和順序由操作符指定。舉例來說,清單 1 是 EBNF 語法 typographify.def,我們在 SimpleParse 那篇文章中見到過這個語法(其它工具運行的方式稍有不同):
- #-*- encoding: gb2312 -*-
- import quopri
- a = "only a test數據"
- b = quopri.encodestring(a) # 對字符串編碼
- print b
- print quopri.decodestring(b) # 對字符串解碼
- import StringIO
- c = StringIO.StringIO()
- d = StringIO.StringIO()
- e = StringIO.StringIO()
- c.write(a)
- c.seek(0)
- quopri.encode(c, d, 0) # 編碼StringIO中的數據, 第三個參數0表示不對空格和tab符號編碼,為1表示進行編碼
- print d.getvalue()
- d.seek(0)
- quopri.decode(d, e) # 解碼StringIO中的數據
- print e.getvalue()
- f1 = open("aaa.txt", "w")
- f1.write(a)
- f1.close()
- f1 = open("aaa.txt", "r")
- f2 = open("bbb.txt", "w")
- quopri.encode(f1, f2, 0) # 編碼aaa.txt中的數據到bbb.txt
- f1.close()
- f2.close()
- print open("bbb.txt", "r").read()
這里有一個有趣的地方。WordScanner 本身是一個完美的掃描程序類;但 Spark 掃描程序類本身可以通過繼承進一步特化:子正則表達式模式在父正則表達式之前匹配,而如果需要,子方法/正則表達式可以覆蓋父方法/正則表達式。
所以,WordPlusScanner 將在 WordScanner 之前對特化進行匹配(可能會因此先獲取一些字節)。模式文檔字符串中允許使用任何正則表達式(舉例來說,.t_contraction() 方法包含模式中的一個“向后插入”)。查找記號的確有一點意思,但真正有意思的是如何向記號列表應用語法。解析階段在記號列表的基礎上創建任意的樹結構。它只是指定了表達式語法而已。
Spark 有好幾種創建 AST 的方法。“手工”的方法是特化 GenericParser 類。在這種情況下,具體子解析器會提供很多方法。方法名的形式為 p_foobar(self, args)。每個這樣的方法的文檔字符串都包含一個或多個模式到名稱的分配。只要語法表達式匹配,每種方法就可以包含任何要執行的代碼。
【編輯推薦】