使用 pyparsing 解析 JSON 格式
Parsing JSON like format with pyparsing
我有两个关于解析 JSON 类数据格式的相关问题
使用 pyparsing
。 目标是解析此数据并将
结果为 JSON.
1)第一类数据看起来像
mystr = """
DataName = {
fieldA = {
fieldB = 10
fieldC = "absf"
}
}
DataName = {
fieldA = {
fieldB = 11
fieldC = "bsf"
}
}
"""
我想知道设置语法的最佳方法是什么
将 mystr
解析为看起来像
的字典列表
expected_result = [{"DataName": {"fieldA": {"fieldB": 10, "fieldC": "absf"}}},
{"DataName": {"fieldA": {"fieldB": 11, "fieldC": "bsf"}}}]
我的第一次尝试如下
from pyparsing import *
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas + '[]')
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
value = (string | number)
jobject = Forward()
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef ^ jobject, delim=LineEnd())
jobject << Dict(field + EQUAL + LBRACE + Optional(members) + RBRACE)
members.parseString(mystr)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-70cbdee9640b> in <module>()
----> 1 members.parseString(mystr)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseString(self, instring, parseAll)
1204 instring = instring.expandtabs()
1205 try:
-> 1206 loc, tokens = self._parse( instring, 0 )
1207 if parseAll:
1208 loc = self.preParse( instring, loc )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2525 # pass False as last arg to _parse for first element, since we already
2526 # pre-parsed the string as part of our And pre-parsing
-> 2527 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2528 errorStop = False
2529 for e in self.exprs[1:]:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2587 for e in self.exprs:
2588 try:
-> 2589 loc2 = e.tryParse( instring, loc )
2590 except ParseException as err:
2591 err.__traceback__ = None
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in tryParse(self, instring, loc)
1112 def tryParse( self, instring, loc ):
1113 try:
-> 1114 return self._parse( instring, loc, doActions=False )[0]
1115 except ParseFatalException:
1116 raise ParseException( instring, loc, self.errmsg, self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2542 raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
2543 else:
-> 2544 loc, exprtokens = e._parse( instring, loc, doActions )
2545 if exprtokens or exprtokens.haskeys():
2546 resultlist += exprtokens
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
3004 def parseImpl( self, instring, loc, doActions=True ):
3005 try:
-> 3006 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
3007 except (ParseException,IndexError):
3008 if self.defaultValue is not _optionalNotMatched:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2525 # pass False as last arg to _parse for first element, since we already
2526 # pre-parsed the string as part of our And pre-parsing
-> 2527 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2528 errorStop = False
2529 for e in self.exprs[1:]:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2587 for e in self.exprs:
2588 try:
-> 2589 loc2 = e.tryParse( instring, loc )
2590 except ParseException as err:
2591 err.__traceback__ = None
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in tryParse(self, instring, loc)
1112 def tryParse( self, instring, loc ):
1113 try:
-> 1114 return self._parse( instring, loc, doActions=False )[0]
1115 except ParseFatalException:
1116 raise ParseException( instring, loc, self.errmsg, self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1076 loc,tokens = self.parseImpl( instring, preloc, doActions )
1077
-> 1078 tokens = self.postParse( instring, loc, tokens )
1079
1080 retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in postParse(self, instring, loc, tokenlist)
3247 tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
3248 else:
-> 3249 dictvalue = tok.copy() #ParseResults(i)
3250 del dictvalue[0]
3251 if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):
AttributeError: 'str' object has no attribute 'copy'
这不起作用,但我不清楚原因。 mystr
是 delimitedList
的
两个 jobject
s (DataName
s) 其中每个 jobject
包含 1 jobject
(fieldA
) 由 1 个 members
和两个 memberDefs
组成。
我在这里错过了什么?
或者,我可以如下定义我的语法
value = Forward()
jobject = Forward()
value << (string | number | Group(jobject))
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members) + RBRACE)
res = members.parseString(mystr)
然后我可以遍历结果并生成字典,但是这
感觉有点乱。
list_of_dicts = []
for pair in res:
list_of_dicts.append({pair[0]: pair[1].asDict()})
print(list_of_dicts)
[{'DataName': {'fieldA': {'fieldC': 'absf', 'fieldB': 10.0}}}, {'DataName': {'fieldA': {'fieldC': 'bsf', 'fieldB': 11.0}}}]
2)数据格式还包括如下文字。
mystr2 = """
fieldA = {
someFieldA[] = {
}
someFieldB[] = {
"typeA", "typeB"
}
someFieldC[] = {
fieldData = {
data = 10
}
fieldData = {
data = 12
}
}
someFieldD = "bsf"
}
fieldA = {
}
"""
我想将其解析为字典列表,如下所示
expected_result2 = [{"fieldA": {"someFieldA": [],
"someFieldB": ["typeA", "typeB"],
"someFieldC":[{"fieldData": {"data": 10}},
{"fieldData": {"data": 10}}],
"someFieldD": "bsf"}},
{"fieldA": {}}]
我试图通过在语法中添加 array
类型来解决这个问题
value = Forward()
jobject = Forward()
arrayElements = delimitedList(string)
array = Group(LBRACE + Optional(arrayElements, []) + RBRACE)
value << (string | number | Group(jobject) | array)
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members) + RBRACE)
res2 = members.parseString(mystr2)
print(res2)
[['fieldA', [['someFieldA[]', []], ['someFieldB', ['typeA', 'typeB']], ['someFieldC[]', [['fieldData', [['data', 10.0]]], ['fieldData', [['data', 12.0]]]]], ['someFieldD', 'bsf']]], ['fieldA', []]]
这个 returns 一个 parseResult 但是我不确定如何进行转换
变成 expected_result2
之类的东西。另外上面的语法中也没有区分
形式的元素
Data = {
}
和
Data[] = {
}
应该分别映射到 {"Data": {}}
和 {"Data": []}
。
编辑
上面mystr2
有错字,someFieldB[] = {
被错误地写成了someFieldB = {
解释 []
重要性的文法如下所示。
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas)
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
scalar_value = (string | number)
value_list = Forward()
jobject = Forward()
memberDef1 = Group(field + EQUAL + scalar_value)
memberDef2 = Group(field + EQUAL + jobject)
memberDef3 = Group(field + "[]" + EQUAL + LBRACE + value_list + RBRACE)
memberDef = memberDef1 | memberDef2 | memberDef3
value_list << (delimitedList(string, ",") | ZeroOrMore(memberDef2))
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members, '{}') + RBRACE)
res = members.parseString(mystr2)
似乎可以正确解析,但是我仍然不清楚如何将 res
转换为字典列表?
编辑 2
下面包含一个说明语法的实际示例
HistoricalDataRequest = {
securities[] = {
"SPY US Equity", "TLT US Equity"
}
fields[] = {
"PX_LAST"
}
startDate = "20150629"
endDate = "20150630"
overrides[] = {
}
}
HistoricalDataResponse = {
securityData = {
security = "SPY US Equity"
eidData[] = {
}
sequenceNumber = 0
fieldExceptions[] = {
}
fieldData[] = {
fieldData = {
date = 2015-06-29
PX_LAST = 205.420000
}
fieldData = {
date = 2015-06-30
PX_LAST = 205.850000
}
}
}
}
HistoricalDataResponse = {
securityData = {
security = "TLT US Equity"
eidData[] = {
}
sequenceNumber = 1
fieldExceptions[] = {
}
fieldData[] = {
fieldData = {
date = 2015-06-29
PX_LAST = 118.280000
}
fieldData = {
date = 2015-06-30
PX_LAST = 117.460000
}
}
}
}
好吧,经过一些骗局和恶作剧,我想我已经发明了一个解析器,可以从这种格式中为您提供 JSON 可用的指令。
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas, alphas+'_')
# was field = Word(alphas)
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
date_expr = Regex(r'\d\d\d\d-\d\d-\d\d')
scalar_value = (string | date_expr | number)
# was scalar_value = (string | number)
list_marker = Suppress("[]")
value_list = Forward()
jobject = Forward()
memberDef1 = Group(field + EQUAL + scalar_value)
memberDef2 = Group(field + EQUAL + jobject)
memberDef3 = Group(field + list_marker + EQUAL + LBRACE + value_list + RBRACE)
memberDef = memberDef1 | memberDef2 | memberDef3
value_list <<= (delimitedList(scalar_value, ",") | ZeroOrMore(Group(Dict(memberDef2))))
value_list.setParseAction(lambda t: [ParseResults(t[:])])
members = OneOrMore(memberDef)
jobject <<= Dict(LBRACE + ZeroOrMore(memberDef) + RBRACE)
# force empty jobject to be a dict
jobject.setParseAction(lambda t: t or {})
parser = members
parser = OneOrMore(Group(Dict(memberDef)))
tests = [mystr, mystr2]
import pprint
import json
for test in tests:
print(test)
res = parser.parseString(test)
for res_dict in res:
pprint.pprint(res_dict.asDict())
# or convert to JSON using:
# print(json.dumps(res_dict.asDict(), indent=2))
print('')
打印(为 someFieldE
添加空 jobject
并为 someFieldF
添加空列表):
{'DataName': {'fieldA': {'fieldB': 10, 'fieldC': 'absf'}}}
{'DataName': {'fieldA': {'fieldB': 11, 'fieldC': 'bsf'}}}
{'fieldA': {'someFieldA': [],
'someFieldB': ['typeA', 'typeB'],
'someFieldC': [{'a': {'data': 10}}, {'a': {'data': 12}}],
'someFieldD': 'bsf',
'someFieldE': {},
'someFieldF': []}}
我使用 Group
围绕 Dict
解决了多个 dict 键,这样重复的键将被隔离到单独的 ParseResults
中。 value_list
上的解析操作在那里,因此列表中的空列表 return 为空 ParseResults
。我不得不强制将空的 jobject
变成字典,因为将它们留空 ParseResults
将没有任何键,因此 return 来自 asDict()
的字典也不会。
(编辑:为了适应您发布的示例,我必须添加“_”作为有效的字段名称字符,并且还为类似日期的字段值定义了一个新的 date_expr
类型。)
我有两个关于解析 JSON 类数据格式的相关问题
使用 pyparsing
。 目标是解析此数据并将
结果为 JSON.
1)第一类数据看起来像
mystr = """
DataName = {
fieldA = {
fieldB = 10
fieldC = "absf"
}
}
DataName = {
fieldA = {
fieldB = 11
fieldC = "bsf"
}
}
"""
我想知道设置语法的最佳方法是什么
将 mystr
解析为看起来像
expected_result = [{"DataName": {"fieldA": {"fieldB": 10, "fieldC": "absf"}}},
{"DataName": {"fieldA": {"fieldB": 11, "fieldC": "bsf"}}}]
我的第一次尝试如下
from pyparsing import *
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas + '[]')
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
value = (string | number)
jobject = Forward()
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef ^ jobject, delim=LineEnd())
jobject << Dict(field + EQUAL + LBRACE + Optional(members) + RBRACE)
members.parseString(mystr)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-70cbdee9640b> in <module>()
----> 1 members.parseString(mystr)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseString(self, instring, parseAll)
1204 instring = instring.expandtabs()
1205 try:
-> 1206 loc, tokens = self._parse( instring, 0 )
1207 if parseAll:
1208 loc = self.preParse( instring, loc )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2525 # pass False as last arg to _parse for first element, since we already
2526 # pre-parsed the string as part of our And pre-parsing
-> 2527 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2528 errorStop = False
2529 for e in self.exprs[1:]:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2587 for e in self.exprs:
2588 try:
-> 2589 loc2 = e.tryParse( instring, loc )
2590 except ParseException as err:
2591 err.__traceback__ = None
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in tryParse(self, instring, loc)
1112 def tryParse( self, instring, loc ):
1113 try:
-> 1114 return self._parse( instring, loc, doActions=False )[0]
1115 except ParseFatalException:
1116 raise ParseException( instring, loc, self.errmsg, self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2542 raise ParseSyntaxException( ParseException(instring, len(instring), self.errmsg, self) )
2543 else:
-> 2544 loc, exprtokens = e._parse( instring, loc, doActions )
2545 if exprtokens or exprtokens.haskeys():
2546 resultlist += exprtokens
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
3004 def parseImpl( self, instring, loc, doActions=True ):
3005 try:
-> 3006 loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
3007 except (ParseException,IndexError):
3008 if self.defaultValue is not _optionalNotMatched:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2525 # pass False as last arg to _parse for first element, since we already
2526 # pre-parsed the string as part of our And pre-parsing
-> 2527 loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
2528 errorStop = False
2529 for e in self.exprs[1:]:
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2587 for e in self.exprs:
2588 try:
-> 2589 loc2 = e.tryParse( instring, loc )
2590 except ParseException as err:
2591 err.__traceback__ = None
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in tryParse(self, instring, loc)
1112 def tryParse( self, instring, loc ):
1113 try:
-> 1114 return self._parse( instring, loc, doActions=False )[0]
1115 except ParseFatalException:
1116 raise ParseException( instring, loc, self.errmsg, self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1070 if self.mayIndexError or loc >= len(instring):
1071 try:
-> 1072 loc,tokens = self.parseImpl( instring, preloc, doActions )
1073 except IndexError:
1074 raise ParseException( instring, len(instring), self.errmsg, self )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in parseImpl(self, instring, loc, doActions)
2799 def parseImpl( self, instring, loc, doActions=True ):
2800 if self.expr is not None:
-> 2801 return self.expr._parse( instring, loc, doActions, callPreParse=False )
2802 else:
2803 raise ParseException("",loc,self.errmsg,self)
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in _parseNoCache(self, instring, loc, doActions, callPreParse)
1076 loc,tokens = self.parseImpl( instring, preloc, doActions )
1077
-> 1078 tokens = self.postParse( instring, loc, tokens )
1079
1080 retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
/home/matthew/anaconda3/lib/python3.5/site-packages/pyparsing.py in postParse(self, instring, loc, tokenlist)
3247 tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
3248 else:
-> 3249 dictvalue = tok.copy() #ParseResults(i)
3250 del dictvalue[0]
3251 if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):
AttributeError: 'str' object has no attribute 'copy'
这不起作用,但我不清楚原因。 mystr
是 delimitedList
的
两个 jobject
s (DataName
s) 其中每个 jobject
包含 1 jobject
(fieldA
) 由 1 个 members
和两个 memberDefs
组成。
我在这里错过了什么?
或者,我可以如下定义我的语法
value = Forward()
jobject = Forward()
value << (string | number | Group(jobject))
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members) + RBRACE)
res = members.parseString(mystr)
然后我可以遍历结果并生成字典,但是这 感觉有点乱。
list_of_dicts = []
for pair in res:
list_of_dicts.append({pair[0]: pair[1].asDict()})
print(list_of_dicts)
[{'DataName': {'fieldA': {'fieldC': 'absf', 'fieldB': 10.0}}}, {'DataName': {'fieldA': {'fieldC': 'bsf', 'fieldB': 11.0}}}]
2)数据格式还包括如下文字。
mystr2 = """
fieldA = {
someFieldA[] = {
}
someFieldB[] = {
"typeA", "typeB"
}
someFieldC[] = {
fieldData = {
data = 10
}
fieldData = {
data = 12
}
}
someFieldD = "bsf"
}
fieldA = {
}
"""
我想将其解析为字典列表,如下所示
expected_result2 = [{"fieldA": {"someFieldA": [],
"someFieldB": ["typeA", "typeB"],
"someFieldC":[{"fieldData": {"data": 10}},
{"fieldData": {"data": 10}}],
"someFieldD": "bsf"}},
{"fieldA": {}}]
我试图通过在语法中添加 array
类型来解决这个问题
value = Forward()
jobject = Forward()
arrayElements = delimitedList(string)
array = Group(LBRACE + Optional(arrayElements, []) + RBRACE)
value << (string | number | Group(jobject) | array)
memberDef = Group(field + EQUAL + value)
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members) + RBRACE)
res2 = members.parseString(mystr2)
print(res2)
[['fieldA', [['someFieldA[]', []], ['someFieldB', ['typeA', 'typeB']], ['someFieldC[]', [['fieldData', [['data', 10.0]]], ['fieldData', [['data', 12.0]]]]], ['someFieldD', 'bsf']]], ['fieldA', []]]
这个 returns 一个 parseResult 但是我不确定如何进行转换
变成 expected_result2
之类的东西。另外上面的语法中也没有区分
Data = {
}
和
Data[] = {
}
应该分别映射到 {"Data": {}}
和 {"Data": []}
。
编辑
上面mystr2
有错字,someFieldB[] = {
被错误地写成了someFieldB = {
解释 []
重要性的文法如下所示。
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas)
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
scalar_value = (string | number)
value_list = Forward()
jobject = Forward()
memberDef1 = Group(field + EQUAL + scalar_value)
memberDef2 = Group(field + EQUAL + jobject)
memberDef3 = Group(field + "[]" + EQUAL + LBRACE + value_list + RBRACE)
memberDef = memberDef1 | memberDef2 | memberDef3
value_list << (delimitedList(string, ",") | ZeroOrMore(memberDef2))
members = delimitedList(memberDef, delim=LineEnd())
jobject << Dict(LBRACE + Optional(members, '{}') + RBRACE)
res = members.parseString(mystr2)
似乎可以正确解析,但是我仍然不清楚如何将 res
转换为字典列表?
编辑 2
下面包含一个说明语法的实际示例
HistoricalDataRequest = {
securities[] = {
"SPY US Equity", "TLT US Equity"
}
fields[] = {
"PX_LAST"
}
startDate = "20150629"
endDate = "20150630"
overrides[] = {
}
}
HistoricalDataResponse = {
securityData = {
security = "SPY US Equity"
eidData[] = {
}
sequenceNumber = 0
fieldExceptions[] = {
}
fieldData[] = {
fieldData = {
date = 2015-06-29
PX_LAST = 205.420000
}
fieldData = {
date = 2015-06-30
PX_LAST = 205.850000
}
}
}
}
HistoricalDataResponse = {
securityData = {
security = "TLT US Equity"
eidData[] = {
}
sequenceNumber = 1
fieldExceptions[] = {
}
fieldData[] = {
fieldData = {
date = 2015-06-29
PX_LAST = 118.280000
}
fieldData = {
date = 2015-06-30
PX_LAST = 117.460000
}
}
}
}
好吧,经过一些骗局和恶作剧,我想我已经发明了一个解析器,可以从这种格式中为您提供 JSON 可用的指令。
LBRACE, RBRACE, EQUAL = map(Suppress, "{}=")
field = Word(alphas, alphas+'_')
# was field = Word(alphas)
string = dblQuotedString().setParseAction(removeQuotes)
number = pyparsing_common.number()
date_expr = Regex(r'\d\d\d\d-\d\d-\d\d')
scalar_value = (string | date_expr | number)
# was scalar_value = (string | number)
list_marker = Suppress("[]")
value_list = Forward()
jobject = Forward()
memberDef1 = Group(field + EQUAL + scalar_value)
memberDef2 = Group(field + EQUAL + jobject)
memberDef3 = Group(field + list_marker + EQUAL + LBRACE + value_list + RBRACE)
memberDef = memberDef1 | memberDef2 | memberDef3
value_list <<= (delimitedList(scalar_value, ",") | ZeroOrMore(Group(Dict(memberDef2))))
value_list.setParseAction(lambda t: [ParseResults(t[:])])
members = OneOrMore(memberDef)
jobject <<= Dict(LBRACE + ZeroOrMore(memberDef) + RBRACE)
# force empty jobject to be a dict
jobject.setParseAction(lambda t: t or {})
parser = members
parser = OneOrMore(Group(Dict(memberDef)))
tests = [mystr, mystr2]
import pprint
import json
for test in tests:
print(test)
res = parser.parseString(test)
for res_dict in res:
pprint.pprint(res_dict.asDict())
# or convert to JSON using:
# print(json.dumps(res_dict.asDict(), indent=2))
print('')
打印(为 someFieldE
添加空 jobject
并为 someFieldF
添加空列表):
{'DataName': {'fieldA': {'fieldB': 10, 'fieldC': 'absf'}}}
{'DataName': {'fieldA': {'fieldB': 11, 'fieldC': 'bsf'}}}
{'fieldA': {'someFieldA': [],
'someFieldB': ['typeA', 'typeB'],
'someFieldC': [{'a': {'data': 10}}, {'a': {'data': 12}}],
'someFieldD': 'bsf',
'someFieldE': {},
'someFieldF': []}}
我使用 Group
围绕 Dict
解决了多个 dict 键,这样重复的键将被隔离到单独的 ParseResults
中。 value_list
上的解析操作在那里,因此列表中的空列表 return 为空 ParseResults
。我不得不强制将空的 jobject
变成字典,因为将它们留空 ParseResults
将没有任何键,因此 return 来自 asDict()
的字典也不会。
(编辑:为了适应您发布的示例,我必须添加“_”作为有效的字段名称字符,并且还为类似日期的字段值定义了一个新的 date_expr
类型。)