2013-10-12 79 views
2

我想將'pyparsing'解析結果作爲字典發佈,而不需要後期處理。爲此,我需要定義我自己的關鍵字符串。以下最好的我可以拿出,產生預期的結果。在pyparsing中,如何分配「不匹配」鍵值?

線解析:

%ADD22C,0.35X*% 

代碼:

import pyparsing as pyp 

floatnum = pyp.Regex(r'([\d\.]+)') 
comma = pyp.Literal(',').suppress() 

cmd_app_def = pyp.Literal('AD').setParseAction(pyp.replaceWith('aperture-definition')) 

cmd_app_def_opt_circ = pyp.Group(pyp.Literal('C') + 
comma).setParseAction(pyp.replaceWith('circle')) 

circular_apperture = pyp.Group(cmd_app_def_opt_circ + 
pyp.Group(pyp.Empty().setParseAction(pyp.replaceWith('diameter')) + floatnum) + 
pyp.Literal('X').suppress()) 

<the grammar for the entire line> 

結果是:

['aperture-definition', '20', ['circle', ['diameter', '0.35']]] 

我認爲這裏一個黑客是

pyp.Empty().setParseAction(pyp.replaceWith('diameter')) 

它總是匹配並且是空的,但是隨後我將所需的密鑰名稱分配給它。

這是最好的方法嗎?我是否濫用pyparsing來做一些它並不意味着做的事情?

+0

我*不要*使用該破解其他地方更多的價值,如'locator'在這個答案美化解析的標記:http://stackoverflow.com/questions/18706631/pyparsing,得到令牌定位功能於結果的名稱/ 18709082#18709082。但是,爲了能夠按名稱訪問已分析的數據項,請使用結果名稱,正如@Thales MG所述。 – PaulMcG

回答

3

在發佈的代碼中查看評論。

import pyparsing as pyp 

comma = pyp.Literal(',').suppress() 
# use parse actions to do type conversion at parse time, so that results fields 
# can immediately be used as ints or floats, without additional int() or float() 
# calls 
floatnum = pyp.Regex(r'([\d\.]+)').setParseAction(lambda t: float(t[0])) 
integer = pyp.Word(pyp.nums).setParseAction(lambda t: int(t[0])) 

# define the command keyword - I assume there will be other commands too, they 
# should follow this general pattern (define the command keyword, then all the 
# options, then define the overall command) 
aperture_defn_command_keyword = pyp.Literal('AD') 

# define a results name for the matched integer - I don't know what this 
# option is, wasn't in your original post 
d_option = 'D' + integer.setResultsName('D') 

# shortcut for defining a results name is to use the expression as a 
# callable, and pass the results name as the argument (I find this much 
# cleaner and keeps the grammar definition from getting messy with lots 
# of calls to setResultsName) 
circular_aperture_defn = 'C' + comma + floatnum('diameter') + 'X' 

# define the overall command 
aperture_defn_command = aperture_defn_command_keyword("command") + d_option + pyp.Optional(circular_aperture_defn) 

# use searchString to skip over '%'s and '*'s, gives us a ParseResults object 
test = "%ADD22C,0.35X*%" 
appData = aperture_defn_command.searchString(test)[0] 

# ParseResults can be accessed directly just like a dict 
print appData['command'] 
print appData['D'] 
print appData['diameter'] 

# or if you prefer attribute-style access to results names 
print appData.command 
print appData.D 
print appData.diameter 

# convert ParseResults to an actual Python dict, removes all unnamed tokens 
print appData.asDict() 

# dump() prints out the parsed tokens as a list, then all named results 
print appData.dump() 

打印:

AD 
22 
0.35 
AD 
22 
0.35 
{'diameter': 0.34999999999999998, 'command': 'AD', 'D': 22} 
['AD', 'D', 22, 'C', 0.34999999999999998, 'X'] 
- D: 22 
- command: AD 
- diameter: 0.35 
4

如果你希望把你的floatnum作爲「直徑」,你可以使用named results

cmd_app_def_opt_circ = pyp.Group(pyp.Literal('C') + 
comma)("circle") 


circular_apperture = pyp.Group(cmd_app_def_opt_circ + 
pyp.Group(floatnum)("diameter") + 
pyp.Literal('X').suppress()) 

這樣,每次解析在circular_appertur方面遇到floatnum時間,這樣的結果被命名爲diameter。另外,如上所述,您可以用相同的方式命名circle。這對你有用嗎?

+0

+1,是的!這正是結果名稱的目的 – PaulMcG

+0

我選擇@PaulMcGuire的答案是因爲它更完整,但您的答案非常有幫助。 –