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