Python 使用pyparsing解析类JSON格式

Python 使用pyparsing解析类JSON格式,python,pyparsing,Python,Pyparsing,关于解析类似JSON的数据格式,我有两个有点相关的问题 使用pyparsing目标是解析此数据并转换 结果转换为JSON。 1)第一类数据如下所示 mystr = """ DataName = { fieldA = { fieldB = 10 fieldC = "absf" } } DataName = { fieldA = { fieldB = 11

关于解析类似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'
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)
expected_result2 = [{"fieldA": {"someFieldA": [],
                               "someFieldB": ["typeA", "typeB"],
                               "someFieldC":[{"fieldData": {"data": 10}},
                                             {"fieldData": {"data": 10}}],
                               "someFieldD": "bsf"}},
                    {"fieldA": {}}]
然后我可以遍历结果并生成字典,但是 感觉有点乱

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 = {
}
"""
我想将其解析为一个字典列表,如下所示

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'
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)
expected_result2 = [{"fieldA": {"someFieldA": [],
                               "someFieldB": ["typeA", "typeB"],
                               "someFieldC":[{"fieldData": {"data": 10}},
                                             {"fieldData": {"data": 10}}],
                               "someFieldD": "bsf"}},
                    {"fieldA": {}}]
我试图通过向语法中添加
数组
类型来解决这个问题

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', []]]

应该分别映射到
{“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)

好的,通过一些欺骗和诡计,我想我已经设计出了一个解析器,可以从这种格式中为您提供支持JSON的DICT

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('')
我使用
Group
绕过
dict
,处理了多个dict键,这样重复的键就会被分离成单独的
ParseResults
。在
value\u list
上的解析操作就在那里,这样空列表在列表中返回空的
ParseResults
。我不得不强制清空
jobject
s成为dict,因为将它们保留为空的
ParseResults
将没有任何键,因此不会从
asDict()
返回dict


(编辑:为了适应您发布的示例,我必须添加“uu”作为有效的字段名字符,并为类似日期的字段值定义一个新的
date\u expr
类型。)

原始数据与您希望作为输出的数据之间存在不一致。一方面,您希望转换
fieldB=10\n fieldC=“absf”
到字典。另一方面,您希望转换相同的构造
DataName={…}\n DataName={…}
进入一个单元素字典列表。DataName是否确实会重复,或者是原始数据中的DataNameA、DataNameB?啊,实际上我现在明白了:第一个示例是第二个示例的子示例,根元素的末尾有
[]
。是的,这是正确的,很抱歉有歧义。
[]
表示一个列表,通过分析格式可以是字符串的逗号分隔列表,如
someFieldB={\n“typeA”,“typeB”\n}
\n
分隔字典的列表,如
someFieldC[]={\n fieldData={\n data=10\n}\n fieldData={\n data=12\n}\n
如果“[]”后缀对于确定值数组的定义很重要,那么您不应该将其隐藏在
字段
的定义中。相反,将
字段+相等+值
声明为与
字段+“[]”+相等+值列表
分开。然后将
值列表
定义为
分隔列表(scalarValue)|一个或多个(jobject)
where
scalar\u value=string | number
@PaulMcGuire谢谢,顺便说一句,很棒的库。我已经编辑了我的问题以包含您的反馈。有没有办法允许
value\u列表
为空,并在这种情况下将默认值设置为
[]
?即形式的字符串
myValue[]={}
?我尝试使用
零或更多
而不是
一个或多个
,但这似乎不支持
默认
参数?感谢您的详细回答。在进一步检查我的数据后,我意识到
字段
实际上也可以包含空格,例如
安全说明=“COQ7 Comdty”
。我试图解决这个问题,在
Word
bodyChars
中添加一个
,即
字段=Word(alphas,alphas++)
但是这会匹配
=
之前的尾随空格。我一直在摸索
Regex
,但似乎找不到正确的表达式可能最简单的方法是将
str.rstrip
作为解析操作添加到
字段
以去除尾随空格:
field=Word(printables+'',excludeChars='=');field.addParseAction(tokenMap(str.rstrip))
或执行此操作以转换为良好的Pythonic标识符:
field.addParseAction(tokenMap(str.rstrip)、tokenMap(str.lower)、tokenMap(str.replace)、'.''.'))
{'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': []}}