在pyparsing中,如何格式化嵌套字典输出?

时间:2013-10-13 12:26:30

标签: python pyparsing

我正在使用pyparsing来解析以下输入:

%FSLAX45Y67*%

我以字典形式出现的输出格式为:

{
  'notation': 'absolute', 
  'zeros': 'leading', 
  'x': {
    'integer': 4, 
    'decimal': 5
  }, 
  'y': {
    'integer': 6, 
    'decimal': 7,
  }, 
  'gerber-command': 'FS'
}

我目前得到的输出是:

{
  'notation': 'absolute', 
  'decimal': 6, 
  'zeros': 'leading', 
  'integer': 6, 
  'y': ([6, 6], {'integer': [(6, 0)], 'decimal': [(6, 1)]}), 
  'x': ([6, 6], {'integer': [(6, 0)], 'decimal': [(6, 1)]}), 
  'gerber-command': 'FS'
 }

(请注意,我的问题不是如何使输出看起来正确,而是如何使pyparsing以我想要的方式排列数据。)

使用以下代码:

single_digit = pyp.Regex(r'(\d)').setParseAction(lambda t: int(t[0]))

cmd_format = pyp.Literal('FS')
cmd_format_opt_leading_zeros = pyp.Literal('L').setParseAction(pyp.replaceWith('leading'))
cmd_format_opt_trailing_zeros = pyp.Literal('T').setParseAction(pyp.replaceWith('trailing'))

format_zeros = ((cmd_format_opt_leading_zeros('zeros')) |
               (cmd_format_opt_trailing_zeros('zeros')))

format_notation = ((cmd_format_opt_absolute('notation')) |
                  (cmd_format_opt_incremental('notation')))

format_data = (single_digit)('integer') + single_digit('decimal')

gformat = (inst_del +
           cmd_format('gerber-command') +
           format_zeros +
           format_notation +
           'X' + (format_data)('x') + 
           'Y' + (format_data)('y') + 
           inst_end +
           inst_del)

(省略了一些微不足道的定义)。有什么建议吗?

3 个答案:

答案 0 :(得分:2)

使用pyparsing Group将结构添加到返回的标记中。这可能会起到作用:

gformat = (inst_del +
           cmd_format('gerber-command') +
           format_zeros +
           format_notation +
           'X' + pyp.Group(format_data)('x') + 
           'Y' + pyp.Group(format_data)('y') + 
           inst_end +
           inst_del)

Pyparsing的默认行为是返回一个平坦的标记列表,以便不根据以什么顺序添加的条件来猜测结构。例如,如果你有这个:

aword = Word("A")
bword = Word("B")
cword = Word("C")

preface = aword + bword
body = cword
ending = aword + bword

totalExpr = preface + body + ending

print totalExpr.parseString("AA BB CCC A B").asList()

pyparsing只返回列表

['AA', 'BB', 'CCC', 'A', 'B']

如果要应用结构(这对于保持嵌套结果名称彼此踩踏尤其重要,正如您在整数和小数的重叠中看到的那样),请使用Group:

totalExpr = Group(preface) + body + Group(ending)

给出:

[['AA', 'BB'], 'CCC', ['A', 'B']]

如果您添加结果名称,这将是这样的:

preface = aword("As") + bword("Bs")
body = cword
ending = aword("As") + bword("Bs")

totalExpr = Group(preface)("preface") + body("body") + Group(ending)("ending")
print totalExpr.parseString("AA BB CCC A B").dump()

给出:

[['AA', 'BB'], 'CCC', ['A', 'B']]
- body: CCC
- ending: ['A', 'B']
  - As: A
  - Bs: B
- preface: ['AA', 'BB']
  - As: AA
  - Bs: BB

因为前言和结尾是分组的,所以“As”和“Bs”的重复名称是分开的。

答案 1 :(得分:1)

您必须自由地使用setParseAction来删除不需要的信息。 在format_data中,您需要一个从single_digit获取输出的函数,并将其转换为您想要的格式。

def _format_data(x):
    return {"integer": x["integer"][0][0],
            "decimal": x["decimal"][0][0]}

format_data.setParseAction(_format_data)

答案 2 :(得分:1)

有趣的是,为什么困难的问题总是以递归结束?

x=\
{
  'notation': 'absolute', 
  'zeros': 'leading', 
  'x': {
    'integer': 4, 
    'decimal': 5
  }, 
  'y': {
    'integer': 6, 
    'decimal': 7,
  }, 
  'gerber-command': 'FS'
}

def superPrint(inidic={},indent='  '):
    for k,v in inidic.items():
        if isinstance(v,dict):
            yield "\n%s'%s': {"%(indent,k)
            for i in superPrint(v,indent+' '*(len(k)+1)):
                yield i
            yield "\n%s},"%indent
        else:
            yield "\n%s'%s': '%s',"%(indent,k,v)

print '{%s\n}'%''.join(superPrint(x))

<强>结果:

{
  'y': {
    'integer': '6',
    'decimal': '7',
  },
  'x': {
    'integer': '4',
    'decimal': '5',
  },
  'zeros': 'leading',
  'notation': 'absolute',
  'gerber-command': 'FS',
}

注意,根据你对问题的描述,我不确定你是否想要一个&#34;,&#34;在字典的最后一个元素中。

尝试更深入:

x=\
{
  'notation': 'absolute', 
  'zeros': 'leading', 
  'x': {
    'integer': 4, 
    'decimal': 5
  }, 
  'y': {
    'integer': 6, 
    'decimal': {'try':7,
                'tryHarder':{'wow':8,
                             'seemsGood':{'wooow':9}}},
  }, 
  'gerber-command': 'FS'
}

print '{%s\n}'%''.join(superPrint(x))

SEEMS好:

{
  'y': {
    'integer': '6',
    'decimal': {
            'try': '7',
            'tryHarder': {
                      'wow': '8',
                      'seemsGood': {
                                'wooow': '9',
                      },
            },
    },
  },
  'x': {
    'integer': '4',
    'decimal': '5',
  },
  'zeros': 'leading',
  'notation': 'absolute',
  'gerber-command': 'FS',
}