1

我正在使用 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)

(省略了一些琐碎的定义)。有什么建议么?

4

3 回答 3

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”是分开的。

于 2013-10-13T16:37:02.147 回答
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)
于 2013-10-13T12:29:32.663 回答
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',
}

注意,根据您对问题的描述,我不确定您是否想要字典的最后一个元素中的“,”。

尝试更深入:

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))

看起来不错:

{
  'y': {
    'integer': '6',
    'decimal': {
            'try': '7',
            'tryHarder': {
                      'wow': '8',
                      'seemsGood': {
                                'wooow': '9',
                      },
            },
    },
  },
  'x': {
    'integer': '4',
    'decimal': '5',
  },
  'zeros': 'leading',
  'notation': 'absolute',
  'gerber-command': 'FS',
}
于 2013-10-13T13:30:36.937 回答