Using the pyparsing module - 使用pyparsing模块
1 操作步驟
為了解析輸入的數(shù)據(jù)字符串,客戶端代碼必須遵循如下步驟:
1. 首先,定義要匹配的各種標(biāo)記(token)和模式(pattern),并且將其賦值給程序變量。可選的結(jié)果名稱和解析動作也可以被定義出來。
2. 基于上面的變量調(diào)用parseString()或scanString()并傳入一個(gè)需要解析的字符串。在解析的過程中,whitespace字符會被忽略掉(當(dāng)然也可以改變這種方式)。當(dāng)標(biāo)記被匹配時(shí),其對應(yīng)定義的解析行為方法將被調(diào)用。
3. 可以像處理字符串列表一樣處理解析后的結(jié)果。如果標(biāo)記調(diào)用setResultsName()設(shè)置了名字,匹配的結(jié)果也可以向字典那樣用名字進(jìn)行訪問。
1.1 Hello,World!
下面用一個(gè)完整的python程序來解析"Hello,World",或其它符合"<問候>,<人>!"形式的問候語。
此些標(biāo)記返回如下格式的內(nèi)容:
['Hello', ',', 'World', '!']
1.2 使用注意事項(xiàng)
pyparsing模塊可以被用來解析簡單的名字字符串或代數(shù)表達(dá)式,同時(shí)也可以從復(fù)雜格式文本報(bào)告中提取數(shù)據(jù)。然后你定義的匹配模式也可能會接收到一個(gè)無效的格式輸入。pyparsing用來從定義良好的數(shù)據(jù)格式中進(jìn)行數(shù)據(jù)提取。
為了代碼的可讀性,利用諸如'+','|','^'或'~'操作符進(jìn)行表達(dá)式的連接。你也可以將一個(gè)字符串與解析表達(dá)式對象進(jìn)行連接-這個(gè)字符串會自動的轉(zhuǎn)換為Literal類型的對象,例如:
? ??
????在equation變量的定義中,字符串'='會自動被解析為Literal('='),這種處理具有更好的可讀性。
pyparsing默認(rèn)的行為是忽略掉whitespace。這種方式滿足99%的使用。這種處理可以讓上面的equation編寫出簡單,干凈,而不用考慮whitespace的亂入。equation語法可以成功的匹配以下語句:
????x=2+2x?=?2+2a?=?10???*???4r=?1234/?100000
? ??
????同時(shí),只要將上例進(jìn)行簡單的擴(kuò)展,就可以支持更復(fù)雜的情況,利用括號的嵌套,浮點(diǎn)數(shù),科學(xué)計(jì)數(shù)法,命名常量(例如e或pi)。請參考example目錄下的fourFn.py。
為了修改pyparing默認(rèn)的忽略whitespace的處理方式,你可以使用以下方法:
使用靜態(tài)方法ParserElement.setDefaultWhitespaceChars進(jìn)行whitespace字符(空格,\r\n\t)的重載。例如當(dāng)定義的語法中換行具有重要的含義,你可以調(diào)用ParserElement.setDefaultWhitespaceChars(' \t')將換行字符從whitespace中移除。通過這種方式的調(diào)用,將會影響到所有pyparsing表達(dá)式的定義。
基于單個(gè)的表達(dá)式調(diào)用leaveWhitespace()。
利用Combine處理多個(gè)表達(dá)式比較彼此相鄰,中間不能有whitespace的情況。例如:
???????real?=?Word(nums)?+?'.'?+?Word(nums)? ??將匹配'3.14159',但同時(shí)也匹配'3 . 12'。并且他回返的匹配結(jié)果為['3', '.', '14159']。
? ? 改變一下此表達(dá)式:
???????real?=?Combine(?Word(nums)?+?'.'?+?Word(nums)?)? ? 它對數(shù)字中間有空格的情況不會匹配,同時(shí)返回一個(gè)連接起來的字符串'3.14159'作為匹配的結(jié) ? ? ? ? 果。
重復(fù)的表達(dá)式定義可以利用'*'操作符。表達(dá)式可以通過制定一個(gè)整數(shù)(表示重復(fù)的次數(shù))來表示重復(fù),或通過數(shù)組定義兩個(gè)整數(shù),或None跟一個(gè)整數(shù)來表示最小和最大的重復(fù)次數(shù)。參考以下示例:
????expr*3 等于 to expr + expr + expr
????expr*(2,3) 等于 expr + expr + Optional(expr)
????expr*(n,None) 或 expr*(n,) 等于 expr*n + ZeroOrMore(expr) (至少n次匹配)
????expr*(None,n) 等于 expr*(0,n) (匹配0到n次)
????expr*(None,None) 等于 ZeroOrMore(expr)
????expr*(1,None) 等于 OneOrMore(expr)
? ? 對于expr*(None,n),如果輸入中存在多于n個(gè)expr的情況,是不會出現(xiàn)解析異常的,如果想得到一場可以寫為expr*(None,n)+~expr。
MatchFirst表達(dá)式執(zhí)行從左到右的匹配,如果第一個(gè)匹配出現(xiàn),那么就忽略掉后續(xù)的表達(dá)式,故需要將特別指定(more-specific)的模式放于稍次于(less-specific)表達(dá)式之前。如果你無法確認(rèn),那么用'Or'表達(dá)式-它會始終匹配最長匹配的表達(dá)式,當(dāng)然會浪費(fèi)一些性能。
'Or'表達(dá)式將解析所有的子表達(dá)式,并將匹配最長輸入數(shù)據(jù)作為結(jié)果。如果出現(xiàn)平局,那么最左邊的表達(dá)式將獲勝。
如果是對一個(gè)文件進(jìn)行解析,那么可以調(diào)用expr.parseFile(sourcefile)方法。
ParseExceptions將報(bào)告表達(dá)式匹配出錯(cuò)的位置。例如,如果我們要對"Hello,World!"進(jìn)行解析,那么如果是"Hello World!",我們將會得到一個(gè)異常,內(nèi)容如下:
????
????在復(fù)雜的表達(dá)式中,只報(bào)告錯(cuò)誤的位置可能是不夠的。可以通過查看ParseException類定義來獲取更好的內(nèi)容。
用Group類對一組有邏輯關(guān)系的匹配進(jìn)行編組。這將幫助解析后的結(jié)果更具備結(jié)構(gòu)層次。
標(biāo)點(diǎn)符號可會與進(jìn)行顯示的匹配,但其自身作為解析結(jié)果的一部分通過沒什么意思。利用supress()方法可以將匹配的內(nèi)容不包含的結(jié)果信息列表中。例如,delimitedList()匹配一系列利用分隔符分割的表達(dá)式,但只返回表達(dá)式匹配的內(nèi)容,分隔符被排除在結(jié)果之外。
解析行為可以用來將字符串轉(zhuǎn)換為其他類型,例如int,float,boolean...
對于復(fù)雜的表達(dá)式,設(shè)置結(jié)果的名字是被推薦的,通過字段的名字訪問匹配結(jié)果的方法比對結(jié)果列表的內(nèi)容進(jìn)行訪問簡單很多,尤其是表達(dá)式中包括可選的部分中。你也可以簡化對setResultsName的訪問:
????可以寫成:
當(dāng)利用解析行為對全局變量或數(shù)據(jù)結(jié)構(gòu)進(jìn)行修改時(shí)要格外的注意,尤其是低級別的標(biāo)記或在and表達(dá)式中的子表達(dá)式;前一個(gè)表達(dá)式的匹配可能會導(dǎo)致后續(xù)的整體匹配失敗。
pyparsing對于復(fù)雜的語法或龐大的輸入處理可能會慢一些。psyco包可以在不修改代碼的情況下提示20%-50%的性能。
2 類
2.1 pyparsing模塊中的類
ParserElement - 所有pyparsing類的抽象基類;方法有:
parseString(sourceString,parseAll=False) - 對于輸入從頭到尾只執(zhí)行一次匹配;返回一個(gè)ParseResults 對象,匹配的結(jié)果可以像列表一樣訪問,也可以選用訪問字典的方式;如果parseAll設(shè)置為True,則對于輸入的字符串無法全部解析的情況將拋出異常。
parseFile(sourceFile) - 處理輸入文件對象或文件名比較方便。文件內(nèi)容將被當(dāng)然一個(gè)字符串傳給parseString()。parseFile同時(shí)也支持parseAll參數(shù)。
scanString(sourceString) - 生成器函數(shù), 在輸入的字符串中查找和提取文本;對于任意的被匹配文本,都將返回如下元組:
????匹配標(biāo)記(ParseResults對象)
????匹配的起始位置
????匹配的結(jié)束位置
????scanString允許隨機(jī)匹配,而不會想parseString那樣嚴(yán)格的進(jìn)行匹配。
transformString(sourceString) - 對scanString進(jìn)行便利的封裝,將輸入字符串中被匹配的部分,利用解析行為進(jìn)行內(nèi)容替換。
searchString(sourceString) - 另一個(gè)對scanString的封裝,返回每次scanString產(chǎn)生的ParseResults對象的列表。
setName(name) - 給予一個(gè)名稱,在發(fā)生異常和產(chǎn)生trace信息時(shí),顯示的更清晰。
setResultsName(string,listAllMatches=False) - 給予一個(gè)名稱;如果此表達(dá)式被重復(fù)組(像ZeroOrMore或者delimitedList)修飾,默認(rèn)只返回最后的匹配結(jié)果 - 如果listAllMatches設(shè)置為True,那么將會返回所有的結(jié)果。
setParseAction(*fn) - 指定一個(gè)或多個(gè)函數(shù)在匹配成功后被調(diào)用;每個(gè)函數(shù)被定義為fn(s,loc,toks):
????s是輸入字符串
????loc是匹配的開始位置
????toks是匹配結(jié)果的列表
????多個(gè)函數(shù)通過多個(gè)setParseAction參數(shù)進(jìn)行指定,或者也可以調(diào)用setParseAction多次。
????每個(gè)解析行為函數(shù)為了進(jìn)行轉(zhuǎn)換或修改字符串內(nèi)容,可以修改toks并返回。例如,fn也可以利用一個(gè)lambda函數(shù)來進(jìn)行字符串轉(zhuǎn)×××的操作:
intNumber?=?Word(nums).setParseAction(?lambda?s,l,t:?[?int(t[0])?]?)????如果fn不需要修改toks列表,它就不必返回。
setBreak(breakFlag=True) - 如果設(shè)置breakFlag為True,則在發(fā)生異常時(shí)調(diào)用pdb.set_break()。
copy() - 返回一個(gè)ParserElement對象的拷貝;可以將相同的表達(dá)式攜帶不同的解析行為用于語法的不同部分。
leaveWhitespace() - 改變默認(rèn)的忽略whitespace行為。
setWhitespaceChars(chars) - 定義一個(gè)字符集合當(dāng)作whitespace處理。
suppress() - 阻止無用元素的匹配輸出,對Suppress對象的封裝。
ignore(expr) - 指定匹配過程中需要忽略的表達(dá)式;在多次匹配過程中重復(fù)的進(jìn)行調(diào)用;經(jīng)常用于處理注釋信息。
setDebug(dbgFlag=True) - 開啟或關(guān)閉匹配過程中的跟蹤信息
validate() - 驗(yàn)證定義的語法是否存在無限遞歸構(gòu)造
parseWithTabs() - 修改默認(rèn)將輸入字符串的tab轉(zhuǎn)換為空格的行為,很少使用。
enablePackrat() - 靜態(tài)方法,用戶開啟緩存來提升性能。
2.2 ParserElement類的子類
Literal - 構(gòu)建一個(gè)字符串用于精確匹配
CaselessLteral - 類似于Literal,不區(qū)分大小寫,返回的結(jié)果是定義的內(nèi)容,而非輸入字符串中的內(nèi)容。
keyword - 類似于Literal,但必須跟隨whitespace,標(biāo)點(diǎn)符號或非關(guān)鍵字字符;阻止非關(guān)鍵字被意外的進(jìn)行匹配。
CaselessKeyword - 類似于keyword,不區(qū)分大小寫
Word - 一個(gè)或多個(gè)聯(lián)系的字符;構(gòu)造的字符串包含一個(gè)初始的字符集作為首字符的匹配,和一個(gè)可選的字符集進(jìn)行后續(xù)字符串的匹配;例如,在C語言中,一個(gè)有效的標(biāo)識符必須以字母表字符或'_'作為開始,接下來的內(nèi)容可以包含數(shù)字。a,i,MAX_LENGTH,_a1,b_109_,plan9FromOuterSpace都是有效的標(biāo)識符;而9b7z,$a,.section,0debug卻不是。用Word定義一個(gè)標(biāo)識符如下:
????如果只有一個(gè)參數(shù),他將認(rèn)為第一個(gè)字符和后續(xù)的字符是一種規(guī)則;例如,定義一個(gè)只能有字符和'_'的標(biāo)識符:
3.2 Expression類的子類
2.4 表達(dá)式運(yùn)算符
2.5 Positional子類
2.6 Converter子類
2.7 特殊的子類
2.8 其他的類
2.9 異常類和問題定位
3 雜項(xiàng)
3.1 輔助方法
3.2 輔助解析動作
3.3 常見的字符串和標(biāo)記?
轉(zhuǎn)載于:https://blog.51cto.com/464559/1626178
總結(jié)
以上是生活随笔為你收集整理的Using the pyparsing module - 使用pyparsing模块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux的常用的命令
- 下一篇: 在VM上安装centOS后的网络配置