使用相同的第一个元素值对令牌进行分组

时间:2018-04-23 20:44:19

标签: pyparsing

给出一个嵌套列表:

(layer 0
    (dielectric FR4)
    (thickness 0.005)
)
(layer 1
    (dielectric copper)
    (thickness 0.01)
)
(layer 2
    (dielectric FR4)
    (thickness 0.005)
)
(physicalLayerGroup "TOP"
    (minLineWidth ALWAYS_CHECK)
    (maxLineWidth ALWAYS_CHECK)
    (maxBondingWireLength NEVER_CHECK)
    (minBondingWireLength NEVER_CHECK)
)
(physicalLayerGroup "L02"
    (minLineWidth ALWAYS_CHECK)
    (maxLineWidth ALWAYS_CHECK)
    (maxBondingWireLength NEVER_CHECK)
    (minBondingWireLength NEVER_CHECK)
)
(physicalLayerGroup "L03"
    (minLineWidth ALWAYS_CHECK)
    (maxLineWidth ALWAYS_CHECK)
    (maxBondingWireLength NEVER_CHECK)
    (minBondingWireLength NEVER_CHECK)
)

即列表,其中每个令牌的第一个元素相同,我该如何对它们进行分组?听起来像addCondition()会适合这个账单,但是如何编码呢?如下所示:

pp.OneOrMore( pp.Word.setName('keyy'), pp.Word.setName('valu'), pp.OneOrMore( pp.ParseResults() ).setParseAction( foo).addCondition( keyy is constant)

有什么想法吗?

code_warrior

1 个答案:

答案 0 :(得分:0)

假设您知道每个组的名称,最简单的方法是按预期名称依次匹配每个组。使用辅助函数(我在下面定义为outer_group)使这更容易:

text = """
(layer 0
    (dielectric FR4)
    (thickness 0.005)
)
... etc. ...
)"""

import pyparsing as pp

LPAR, RPAR = map(pp.Suppress, "()")
key_expr = pp.Word(pp.alphas)
qs = pp.quotedString().addParseAction(pp.removeQuotes)
val_expr = pp.pyparsing_common.number | qs | pp.Word(pp.printables, excludeChars='()')

# Dict keys need to be converted to str's
subgroup_key = val_expr().addParseAction(lambda t: str(t[0]))
subgroup = pp.Dict(pp.OneOrMore(pp.Group(LPAR + key_expr + val_expr + RPAR)))

# use this method to define each group by name
def outer_group(group_name):
    lookahead = pp.FollowedBy(LPAR + pp.Suppress(group_name))
    return lookahead + pp.Dict(pp.ZeroOrMore(pp.Group(LPAR 
                                              + pp.Suppress(group_name) 
                                              + subgroup_key
                                              + subgroup 
                                              + RPAR)))(group_name)

# define groups by name as given in the posted question
# '&' operator generates an Each expression, which allows the groups to be
# parsed in any order
parser = outer_group('layer') & outer_group('physicalLayerGroup')

# how it works
data = parser.parseString(text)
print(data.dump())
print(data.layer['0'].dielectric)
print(data.physicalLayerGroup.TOP.maxLineWidth)

打印:

[[['0', ['dielectric', 'FR4'], ['thickness', 0.005]], ['1', ['dielectric', 'copper'], ['thickness', 0.01]], ['2', ['dielectric', 'FR4'], ['thickness', 0.005]]], [['TOP', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']], ['L02', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']], ['L03', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']]]]
- layer: [['0', ['dielectric', 'FR4'], ['thickness', 0.005]], ['1', ['dielectric', 'copper'], ['thickness', 0.01]], ['2', ['dielectric', 'FR4'], ['thickness', 0.005]]]
  - 0: [['dielectric', 'FR4'], ['thickness', 0.005]]
    - dielectric: 'FR4'
    - thickness: 0.005
  - 1: [['dielectric', 'copper'], ['thickness', 0.01]]
    - dielectric: 'copper'
    - thickness: 0.01
  - 2: [['dielectric', 'FR4'], ['thickness', 0.005]]
    - dielectric: 'FR4'
    - thickness: 0.005
- physicalLayerGroup: [['TOP', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']], ['L02', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']], ['L03', ['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']]]
  - L02: [['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']]
    - maxBondingWireLength: 'NEVER_CHECK'
    - maxLineWidth: 'ALWAYS_CHECK'
    - minBondingWireLength: 'NEVER_CHECK'
    - minLineWidth: 'ALWAYS_CHECK'
  - L03: [['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']]
    - maxBondingWireLength: 'NEVER_CHECK'
    - maxLineWidth: 'ALWAYS_CHECK'
    - minBondingWireLength: 'NEVER_CHECK'
    - minLineWidth: 'ALWAYS_CHECK'
  - TOP: [['minLineWidth', 'ALWAYS_CHECK'], ['maxLineWidth', 'ALWAYS_CHECK'], ['maxBondingWireLength', 'NEVER_CHECK'], ['minBondingWireLength', 'NEVER_CHECK']]
    - maxBondingWireLength: 'NEVER_CHECK'
    - maxLineWidth: 'ALWAYS_CHECK'
    - minBondingWireLength: 'NEVER_CHECK'
    - minLineWidth: 'ALWAYS_CHECK'
FR4
ALWAYS_CHECK

通过调用asDict()

将解析后的结构转换为JSON
# emit JSON from parsed results
import json
print(json.dumps(data.asDict(), indent='  '))

打印:

{
  "physicalLayerGroup": {
    "TOP": {
      "minBondingWireLength": "NEVER_CHECK",
      "minLineWidth": "ALWAYS_CHECK",
      "maxBondingWireLength": "NEVER_CHECK",
      "maxLineWidth": "ALWAYS_CHECK"
    },
    "L02": {
      "minBondingWireLength": "NEVER_CHECK",
      "minLineWidth": "ALWAYS_CHECK",
      "maxBondingWireLength": "NEVER_CHECK",
      "maxLineWidth": "ALWAYS_CHECK"
    },
    "L03": {
      "minBondingWireLength": "NEVER_CHECK",
      "minLineWidth": "ALWAYS_CHECK",
      "maxBondingWireLength": "NEVER_CHECK",
      "maxLineWidth": "ALWAYS_CHECK"
    }
  },
  "layer": {
    "0": {
      "dielectric": "FR4",
      "thickness": 0.005
    },
    "1": {
      "dielectric": "copper",
      "thickness": 0.01
    },
    "2": {
      "dielectric": "FR4",
      "thickness": 0.005
    }
  }
}